C# Linq to SQL Concat/Union在自定义类上不起作用
Linq to SQL Concat/Union在自定义类上不起作用 自定义类 工会: 执行上述查询时,我得到以下错误: “Distinct”操作无法应用于集合 指定参数的结果类型。\r\n参数名称:参数 海螺 执行上述查询时,我得到以下错误: {不支持嵌套查询。Operation1='UnionAll' 操作2='MultiStreamNest'} 最后,我要做的是,如果Users表的Auth字段为true,则我希望AuthTrue表中的数据存储在列表字段中,如果Users表的Auth字段为false,则我希望AuthFalse表中的数据存储在列表字段中 我希望所有这些都能在单个查询或最多2到3个查询中完成C# Linq to SQL Concat/Union在自定义类上不起作用,c#,.net,linq,linq-to-sql,linq-to-entities,C#,.net,Linq,Linq To Sql,Linq To Entities,Linq to SQL Concat/Union在自定义类上不起作用 自定义类 工会: 执行上述查询时,我得到以下错误: “Distinct”操作无法应用于集合 指定参数的结果类型。\r\n参数名称:参数 海螺 执行上述查询时,我得到以下错误: {不支持嵌套查询。Operation1='UnionAll' 操作2='MultiStreamNest'} 最后,我要做的是,如果Users表的Auth字段为true,则我希望AuthTrue表中的数据存储在列表字段中,如果Users表的Auth字段为f
谢谢。您应该像这样重写您的Concat尝试: 1.从用户开始 2.然后对AuthFalse和AuthTrue执行两个左连接 3.添加按用户进行筛选。验证字段和正确的右匹配 4.请选择与user.Id、user.LastName、user.FirstName+AuthFalse匹配或AuthTrue匹配的匿名类。在这个阶段,可查询的必须由可计算的浇铸而成 5.然后剩下的就是正确的分组+选择 以下是完整单元测试的步骤:
public class CustomClass
{
public string FirstName { get; set; }
public string LastName { get; set; }
public List<CustomAccesses> Accesses { get; set; }
}
public class CustomAccesses
{
public int Rights { get; set; }
}
public class Accesses
{
public Guid ID { get; set; }
public Guid UID { get; set; }
public int Rights { get; set; }
}
public class User
{
public Guid ID { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public bool Auth { get; set; }
}
[TestFixture]
public class QueryTests
{
private static readonly User TrueUser = new User
{
ID = Guid.NewGuid(),
FirstName = "TrueFirstName",
LastName = "TrueLastName",
Auth = true
};
private static readonly User FalseUser = new User
{
ID = Guid.NewGuid(),
FirstName = "FalseFirstName",
LastName = "FalseLastName",
Auth = false
};
private static readonly User[] DbUsersMock =
{
TrueUser,
FalseUser
};
private static readonly Accesses[] DbAuthTrueMock =
{
new Accesses
{
ID = Guid.NewGuid(),
UID = TrueUser.ID,
Rights = 1
},
new Accesses
{
ID = Guid.NewGuid(),
UID = TrueUser.ID,
Rights = 2
}
};
private static readonly Accesses[] DbAuthFalseMock =
{
new Accesses
{
ID = Guid.NewGuid(),
UID = FalseUser.ID,
Rights = -1
},
new Accesses
{
ID = Guid.NewGuid(),
UID = FalseUser.ID,
Rights = -2
}
};
[Test]
public void Test()
{
var users = DbUsersMock.AsQueryable();
var authTrue = DbAuthTrueMock.AsQueryable();
var authFalse = DbAuthFalseMock.AsQueryable();
var result = users
.GroupJoin(
authTrue,
u => u.ID,
ta => ta.UID,
(user, accesses) => new
{
user,
accesses = accesses.DefaultIfEmpty()
}
)
.SelectMany(
ua => ua
.accesses
.Select(
trueAccess => new
{
ua.user,
trueAccess
}
)
)
.GroupJoin(
authFalse,
ua => ua.user.ID,
fa => fa.UID,
(userAccess, accesses) => new
{
userAccess,
accesses = accesses.DefaultIfEmpty()
}
)
.SelectMany(
uaa => uaa
.accesses
.Select(
falseAccess => new
{
uaa.userAccess.user,
uaa.userAccess.trueAccess,
falseAccess
}
)
)
.Where(
uaa => uaa.user.Auth
? uaa.trueAccess != null
: uaa.falseAccess != null
)
.Select(
uaa => new
{
uaa.user.ID,
uaa.user.FirstName,
uaa.user.LastName,
AccessID = uaa.user.Auth
? uaa.trueAccess.ID
: uaa.falseAccess.ID,
Rights = uaa.user.Auth
? uaa.trueAccess.Rights
: uaa.falseAccess.Rights
}
)
.OrderBy(uaa => uaa.ID)
.AsEnumerable()
.GroupBy(uaa => uaa.ID)
.Select(
g => new CustomClass
{
FirstName = g.First().FirstName,
LastName = g.First().LastName,
Accesses = g
.GroupBy(uaa => uaa.AccessID)
.Select(
uaa => new CustomAccesses
{
Rights = uaa.First().Rights
}
)
.ToList()
}
)
.ToArray();
Assert.That(result.Length, Is.EqualTo(DbUsersMock.Length));
}
}
你可以用很多方法来做。一个简单的方法是: 拿两张清单,一张是正确的,另一张是错误的。然后在结果列表中使用ADDRANGE方法。 此方法ADDRANGE仅在处理列表时有效 例如:
var listTrue = ctx.Users.Where(...).Select(s=> new CustomClass{...}).ToList();
var listFalse = ctx.Users.Where(...).Select(s=> new CustomClass{...}).ToList();
var result = new List<CustomClass>();
result.AddRange(listTrue);
result.AddRange(listFalse);
return result;
可能您应该像这样重写您的Concat尝试:从用户开始,然后对AuthFalse和AuthTrue执行两个左连接添加按用户进行筛选。Auth字段和正确的右匹配,选择具有user.Id、user.LastName、user.FirstName+AuthFalse匹配或AuthTrue匹配的匿名类。在这一阶段,可查询必须通过铸造到可计算,然后剩下的就是正确的分组+选择。@Vitaliykalin,谢谢,你能提供一些代码片段吗?因为我不明白你想说什么来实现。谢谢,你使用了AsEnumerable方法来触发查询,但我不想触发查询,因为在那之后我必须添加搜索关键字条件和排序功能。所有这些我都想在数据库上而不是内存中完成。我已经将一个numerable放在LinqToSql能够正确处理您的需求的地方。若你们的描述是不完整的,那个么你们应该准备好不完整的解决方案。实际上,这段代码是我作为注释发布的解释片段。我将复制粘贴我的评论作为回答。
IQueryable<CustomClass> objQuery = context.Users
.Where(W => W.Auth == true)
.Select(S => new CustomClass()
{
FirstName = S.FirstName,
LastName = S.LastName,
Accesses = context.AuthFalse
.Where(W => W.UID = S.ID)
.Select(S1 => new Accesses()
{
AccessesID = S1.AccessesID,
})
.ToList(),
})
.Concat(context.Users
.Where(W => W.Auth == true)
.Select(S => new CustomClass()
{
FirstName = S.FirstName,
LastName = S.LastName,
Accesses = context.AuthTrue
.Where(W => W.UID = S.ID)
.Select(S1 => new Accesses()
{
AccessesID = S1.AccessesID,
})
.ToList(),
})
);
public class CustomClass
{
public string FirstName { get; set; }
public string LastName { get; set; }
public List<CustomAccesses> Accesses { get; set; }
}
public class CustomAccesses
{
public int Rights { get; set; }
}
public class Accesses
{
public Guid ID { get; set; }
public Guid UID { get; set; }
public int Rights { get; set; }
}
public class User
{
public Guid ID { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public bool Auth { get; set; }
}
[TestFixture]
public class QueryTests
{
private static readonly User TrueUser = new User
{
ID = Guid.NewGuid(),
FirstName = "TrueFirstName",
LastName = "TrueLastName",
Auth = true
};
private static readonly User FalseUser = new User
{
ID = Guid.NewGuid(),
FirstName = "FalseFirstName",
LastName = "FalseLastName",
Auth = false
};
private static readonly User[] DbUsersMock =
{
TrueUser,
FalseUser
};
private static readonly Accesses[] DbAuthTrueMock =
{
new Accesses
{
ID = Guid.NewGuid(),
UID = TrueUser.ID,
Rights = 1
},
new Accesses
{
ID = Guid.NewGuid(),
UID = TrueUser.ID,
Rights = 2
}
};
private static readonly Accesses[] DbAuthFalseMock =
{
new Accesses
{
ID = Guid.NewGuid(),
UID = FalseUser.ID,
Rights = -1
},
new Accesses
{
ID = Guid.NewGuid(),
UID = FalseUser.ID,
Rights = -2
}
};
[Test]
public void Test()
{
var users = DbUsersMock.AsQueryable();
var authTrue = DbAuthTrueMock.AsQueryable();
var authFalse = DbAuthFalseMock.AsQueryable();
var result = users
.GroupJoin(
authTrue,
u => u.ID,
ta => ta.UID,
(user, accesses) => new
{
user,
accesses = accesses.DefaultIfEmpty()
}
)
.SelectMany(
ua => ua
.accesses
.Select(
trueAccess => new
{
ua.user,
trueAccess
}
)
)
.GroupJoin(
authFalse,
ua => ua.user.ID,
fa => fa.UID,
(userAccess, accesses) => new
{
userAccess,
accesses = accesses.DefaultIfEmpty()
}
)
.SelectMany(
uaa => uaa
.accesses
.Select(
falseAccess => new
{
uaa.userAccess.user,
uaa.userAccess.trueAccess,
falseAccess
}
)
)
.Where(
uaa => uaa.user.Auth
? uaa.trueAccess != null
: uaa.falseAccess != null
)
.Select(
uaa => new
{
uaa.user.ID,
uaa.user.FirstName,
uaa.user.LastName,
AccessID = uaa.user.Auth
? uaa.trueAccess.ID
: uaa.falseAccess.ID,
Rights = uaa.user.Auth
? uaa.trueAccess.Rights
: uaa.falseAccess.Rights
}
)
.OrderBy(uaa => uaa.ID)
.AsEnumerable()
.GroupBy(uaa => uaa.ID)
.Select(
g => new CustomClass
{
FirstName = g.First().FirstName,
LastName = g.First().LastName,
Accesses = g
.GroupBy(uaa => uaa.AccessID)
.Select(
uaa => new CustomAccesses
{
Rights = uaa.First().Rights
}
)
.ToList()
}
)
.ToArray();
Assert.That(result.Length, Is.EqualTo(DbUsersMock.Length));
}
}
var listTrue = ctx.Users.Where(...).Select(s=> new CustomClass{...}).ToList();
var listFalse = ctx.Users.Where(...).Select(s=> new CustomClass{...}).ToList();
var result = new List<CustomClass>();
result.AddRange(listTrue);
result.AddRange(listFalse);
return result;