我正在尝试使用 linq 在存储在 Apache Ignite 中的两个表之间进行左连接。它是一个 C# 控制台应用程序。我正在使用 .NET 6 以及 Apache.Ignite 2.16.0 和 Apache.Ignite.Linq 2.16.0 作为 NuGet 包。我正在运行 Windows 10 AMD64 和 Apache Ignite 版本 2.16.0 请找到下面的代码:
static void Main(string[] args)
{
try
{
var cfg = new IgniteClientConfiguration
{
Endpoints = new[] { "127.0.0.1:10800" }
};
using (var client = Ignition.StartClient(cfg))
{
var empQueryEntity = new QueryEntity(typeof(int), typeof(Employee));
var empCacheConfig = new CacheClientConfiguration("employee-cache", empQueryEntity);
var empCache = client.GetOrCreateCache<int, Employee>(empCacheConfig);
empCache.Query(new SqlFieldsQuery("CREATE TABLE IF NOT EXISTS Employee " +
"(id int primary key, " +
"name varchar, " +
"age int, " +
"departmentId int)")).GetAll();
empCache.Query(
new SqlFieldsQuery("INSERT INTO Employee (_key, id, name, age, departmentId) " +
"VALUES (1, 1, 'john williams', 25, 1), " +
"(2, 2, 'danny kent', 30, 2), " +
"(3, 3, 'julian shea', 25, 1), " +
"(4, 4, 'dave white', 55, 1) ")
).GetAll();
empCache.Query(
new SqlFieldsQuery("INSERT INTO Employee (_key, id, name, age) " +
"VALUES (5, 5, 'robin harrison', 26)")
).GetAll();
var deptQueryEntity = new QueryEntity(typeof(int), typeof(Department));
var deptCacheConfig = new CacheClientConfiguration("department-cache", deptQueryEntity);
var deptCache = client.GetOrCreateCache<int, Department>(deptCacheConfig);
deptCache.Query(new SqlFieldsQuery("CREATE TABLE IF NOT EXISTS DEPARTMENT (" +
"id int primary key, " +
"name varchar, " +
"city varchar)")
).GetAll();
deptCache.Query(
new SqlFieldsQuery("INSERT INTO DEPARTMENT (_key, id, name, city) " +
" VALUES (1, 1, 'engineering', 'new jersey')," +
"(2, 2, 'operations', 'new york') ")
).GetAll();
IQueryable<ICacheEntry<int, Employee>> employees = empCache.AsCacheQueryable();
IQueryable<ICacheEntry<int, Department>> departments = deptCache.AsCacheQueryable();
//left join - not working
var query1 =
from employee in employees
join department in departments on employee.Value.DepartmentId equals department.Value.Id into jt
from record in jt.DefaultIfEmpty()
select new
{
empName = employee.Value.Name,
deptName = record==null ? "" : record.Value.Name
};
//left join - not working
var query2 = employees.GroupJoin(departments, employee => employee.Value.DepartmentId, department => department.Value.Id,
(employee, department) => new { employee, subgroup = department.DefaultIfEmpty() })
.Select(gj => new
{
empName = gj.employee.Value.Name,
deptName = gj.subgroup.FirstOrDefault().Value.Name ?? string.Empty
});
//left join - not working
var query3 =
from employee in employees
from department in departments
.Where(d => employee.Value.DepartmentId == d.Value.Id)
.DefaultIfEmpty()
select new {
empName = employee.Value.Name,
deptName = department.Value.Name };
//left join - not working
// https://stackoverflow.com/questions/6662887/how-to-achieve-left-excluding-join-using-linq
var query4 =
from employee in employees
join department in departments on employee.Value.DepartmentId equals department.Value.Id into jt
from b in jt.DefaultIfEmpty()
where b == null
select new { empName = employee.Value.Name,
deptName = b.Value.Name };
//inner join - working
var query5 =
from employee in employees
join department in departments on employee.Value.DepartmentId equals department.Value.Id
select new
{
empName = employee.Value.Name,
deptName = department.Value.Name
};
//left join - working
var query6 = empCache.Query(new SqlFieldsQuery("select t1.name, t2.name from \"employee-cache\".Employee as t1 left join \"department-cache\".Department t2 on t1.departmentId = t2.id")).GetAll();
foreach (var rec in query1)
{
Console.WriteLine(rec.empName + ": " + rec.deptName);
}
}
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
}
}
class Employee
{
[QuerySqlField]
public int Id { get; set; }
[QuerySqlField]
public string Name { get; set; }
[QuerySqlField]
public int Age { get; set; }
[QuerySqlField]
public int DepartmentId { get; set; }
public Employee()
{
Random random = new Random();
Id = random.Next();
}
}
class Department
{
[QuerySqlField]
public int Id { get; set; }
[QuerySqlField]
public string Name { get; set; }
[QuerySqlField]
public string City { get; set; }
public Department()
{
Random random = new Random();
Id = random.Next();
}
}
我尝试了 linq 查询和方法语法。他们没有工作。怀疑我的设置可能有一些错误,我尝试使用 linq 进行内部联接,并使用 sql 进行外部联接。他们都工作了。然而,通过 linq 的左连接给出了一个例外:
System.NotSupportedException: Unexpected query source: join ICacheEntry`2 department in CacheQueryable [CacheName=department-cache, TableName=DEPARTMENT, Query=SqlFieldsQuery [Sql=select _T0._KEY, _T0._VAL from "department-cache".DEPARTMENT as _T0, Arguments=[], Local=False, PageSize=1024, EnableDistributedJoins=False, EnforceJoinOrder=False, Timeout=00:00:00, Partitions=[], UpdateBatchSize=1, Colocated=False, Schema=, Lazy=False]] on [employee].Value.DepartmentId equals [department].Value.Id into IEnumerable`1 jt
at Apache.Ignite.Linq.Impl.ExpressionWalker.GetQuerySource(Expression expression, MemberExpression memberHint)
at Apache.Ignite.Linq.Impl.ExpressionWalker.GetQuerySource(Expression expression, MemberExpression memberHint)
at Apache.Ignite.Linq.Impl.ExpressionWalker.GetQuerySource(Expression expression, MemberExpression memberHint)
at Apache.Ignite.Linq.Impl.ExpressionWalker.GetQuerySource(Expression expression, MemberExpression memberHint)
at Apache.Ignite.Linq.Impl.AliasDictionary.GetTableAlias(Expression expression)
at Apache.Ignite.Linq.Impl.CacheQueryExpressionVisitor.VisitQuerySourceReference(QuerySourceReferenceExpression expression)
at Remotion.Linq.Clauses.Expressions.QuerySourceReferenceExpression.Accept(ExpressionVisitor visitor)
at System.Linq.Expressions.ExpressionVisitor.Visit(Expression node)
at Remotion.Linq.Parsing.ThrowingExpressionVisitor.Visit(Expression expression)
at Apache.Ignite.Linq.Impl.CacheQueryExpressionVisitor.Visit(Expression expression)
at Apache.Ignite.Linq.Impl.CacheQueryExpressionVisitor.VisitBinary(BinaryExpression expression)
at System.Linq.Expressions.BinaryExpression.Accept(ExpressionVisitor visitor)
at System.Linq.Expressions.ExpressionVisitor.Visit(Expression node)
at Remotion.Linq.Parsing.ThrowingExpressionVisitor.Visit(Expression expression)
at Apache.Ignite.Linq.Impl.CacheQueryExpressionVisitor.Visit(Expression expression)
at Apache.Ignite.Linq.Impl.CacheQueryExpressionVisitor.VisitConditional(ConditionalExpression expression)
at System.Linq.Expressions.ConditionalExpression.Accept(ExpressionVisitor visitor)
at System.Linq.Expressions.ExpressionVisitor.Visit(Expression node)
at Remotion.Linq.Parsing.ThrowingExpressionVisitor.Visit(Expression expression)
at Apache.Ignite.Linq.Impl.CacheQueryExpressionVisitor.Visit(Expression expression)
at Apache.Ignite.Linq.Impl.CacheQueryExpressionVisitor.VisitArguments(IEnumerable`1 arguments)
at Apache.Ignite.Linq.Impl.CacheQueryExpressionVisitor.VisitNew(NewExpression expression)
at System.Linq.Expressions.NewExpression.Accept(ExpressionVisitor visitor)
at System.Linq.Expressions.ExpressionVisitor.Visit(Expression node)
at Remotion.Linq.Parsing.ThrowingExpressionVisitor.Visit(Expression expression)
at Apache.Ignite.Linq.Impl.CacheQueryExpressionVisitor.Visit(Expression expression)
at Apache.Ignite.Linq.Impl.CacheQueryModelVisitor.BuildSqlExpression(Expression expression, Boolean useStar, Boolean includeAllFields, Boolean visitSubqueryModel)
at Apache.Ignite.Linq.Impl.CacheQueryModelVisitor.VisitSelectors(QueryModel queryModel, Boolean includeAllFields)
at Apache.Ignite.Linq.Impl.CacheQueryModelVisitor.VisitQueryModel(QueryModel queryModel, Boolean includeAllFields, Boolean copyAliases)
at Apache.Ignite.Linq.Impl.CacheQueryModelVisitor.VisitQueryModel(QueryModel queryModel)
at Apache.Ignite.Linq.Impl.CacheQueryModelVisitor.GenerateQuery(QueryModel queryModel)
at Apache.Ignite.Linq.Impl.CacheFieldsQueryExecutor.GetQueryData(QueryModel queryModel)
at Apache.Ignite.Linq.Impl.CacheFieldsQueryExecutor.ExecuteCollection[T](QueryModel queryModel)
at Remotion.Linq.Clauses.StreamedData.StreamedSequenceInfo.ExecuteCollectionQueryModel[T](QueryModel queryModel, IQueryExecutor executor)
at Remotion.Linq.Clauses.StreamedData.StreamedSequenceInfo.ExecuteQueryModel(QueryModel queryModel, IQueryExecutor executor)
at Remotion.Linq.QueryModel.Execute(IQueryExecutor executor)
at Apache.Ignite.Linq.Impl.CacheFieldsQueryProvider.Execute(Expression expression)
at Apache.Ignite.Linq.Impl.CacheFieldsQueryProvider.Execute[TResult](Expression expression)
at Remotion.Linq.QueryableBase`1.GetEnumerator()
Apache Ignite 按照 [1] 支持 LEFT OUTER JOIN
请让我知道我在哪里犯了错误,或者我这边提供更多信息。
[1] - https://ignite.apache.org/docs/latest/sql-reference/sql-conformance
谢谢你。
我已经尝试过:
工作过
失败 5)使用 linq 的方法语法运行相同的查询 6) 尝试了如何使用 LINQ 实现 Left Exclusion JOIN? 中给出的代码 出现错误:
System.NotSupportedException
HResult=0x80131515
Message=FROM clause must be IQueryable: from ICacheEntry`2 b in {[jt] => DefaultIfEmpty()}
Source=Apache.Ignite.Linq
StackTrace:
at Apache.Ignite.Linq.Impl.CacheQueryModelVisitor.ValidateFromClause(IFromClause clause)
at Apache.Ignite.Linq.Impl.CacheQueryModelVisitor.VisitMainFromClause(MainFromClause fromClause, QueryModel queryModel)
at Remotion.Linq.QueryModelVisitorBase.VisitQueryModel(QueryModel queryModel)
at Apache.Ignite.Linq.Impl.CacheQueryModelVisitor.VisitQueryModel(QueryModel queryModel, Boolean includeAllFields, Boolean copyAliases)
at Apache.Ignite.Linq.Impl.CacheQueryModelVisitor.GenerateQuery(QueryModel queryModel)
at Apache.Ignite.Linq.Impl.CacheFieldsQueryExecutor.ExecuteCollection[T](QueryModel queryModel)
at Remotion.Linq.Clauses.StreamedData.StreamedSequenceInfo.ExecuteQueryModel(QueryModel queryModel, IQueryExecutor executor)
at Apache.Ignite.Linq.Impl.CacheFieldsQueryProvider.Execute[TResult](Expression expression)
at Remotion.Linq.QueryableBase`1.GetEnumerator()
at IgniteTest.Program.Main(String[] args) in C:\Users\vince\source\repos\ApacheIgniteExample\ApacheIgniteExample\Program.cs:line 202
This exception was originally thrown at this call stack:
[External Code]
IgniteTest.Program.Main(string[]) in Program.cs
Join
代替 GroupJoin
DefaultIfEmpty
执行 left outer
join这适用于您的示例:
var linqLeftJoin = employees.Join(
departments.DefaultIfEmpty(),
employee => employee.Value.DepartmentId,
department => department.Value.Id,
(employee, jt) => new { empName = employee.Value.Name, deptName = jt.Value.Name });
foreach (var rec in linqLeftJoin)
{
Console.WriteLine(rec.empName + ": " + rec.deptName);
}