我一直在尝试一些技巧,但仍然找不到我满意的东西。
如果我做类似的事情;
IQueryable<TestClass> tests = new MyDbContext()
.LdbRecords
.Select(r => new TestClass() { Id = r.RecordId, Name = r.RecordName });
Console.WriteLine(tests.Count());
EF执行相对明智的查询;
SELECT
[GroupBy1].[A1] AS [C1]
FROM ( SELECT
COUNT(1) AS [A1]
FROM [dbo].[ldb_record] AS [Extent1]
) AS [GroupBy1]
我试图摆脱使用无参数构造函数的情况。主要目标是-当我们添加新属性时,不必费心去更新每个新的类实例。取而代之的是,我们修改构造函数,这将破坏更新该类的所有代码段,直到添加了其他参数(确保我们不会忘记在任何地方添加新的属性映射)。如果有更好的方法可以做到这一点,那么我就不知所措!
构造函数如下;
public TestClass(int id, string name)
{
Id = id;
Name = name;
}
到目前为止,我发现了每种技术;例如
IEnumerable<TestClass> tests = new MyDbContext()
.LdbRecords
.AsEnumerable()
.Select(r => new TestClass(r.RecordId, r.RecordName));
Console.WriteLine(tests.Count());
对SQL查询的生成有不利影响;
SELECT
[Extent1].[record_id] AS [record_id],
[Extent1].[record_name] AS [record_name],
[Extent1].[record_note] AS [record_note]
FROM [dbo].[ldb_record] AS [Extent1]
是否有一种我可以使用的技术(也许使用委托,表达式或函数?)可以使我使用我的TestClass
构造函数而无需枚举?
我很高兴在TestClass中有一个私有的无参数构造函数,函数/委托等可以调用该构造函数?
谢谢
答案 0 :(得分:0)
我想出了
IQueryable<TestClass> tests = new MyDbContext()
.LdbRecords
.Select(TestClass.ConvertPoco);
Console.WriteLine(tests.Count());
public class TestClass
{
public int Id { get; set; }
public string Name { get; set; }
private TestClass()
{
}
public TestClass(int id, string name)
{
Id = id;
Name = name;
}
public static Expression<Func<LdbRecord, TestClass>> ConvertPoco
{
get
{
return p => new TestClass() { Id = p.RecordId, Name = p.RecordName };
}
}
}
与无参数构造函数技术得出的查询结果完全相同;
SELECT
[GroupBy1].[A1] AS [C1]
FROM ( SELECT
COUNT(1) AS [A1]
FROM [dbo].[ldb_record] AS [Extent1]
) AS [GroupBy1]
对此有何进展?
答案 1 :(得分:0)
您产生的SQL是不同的,因为它们返回的结果是不同的。在第一个示例中,(最后)您要求数据库提供的只是一个计数,Linq为您提供了一个计数。您永远不会使用实体本身,因此Linq永远不会查询它们。
在第二个示例中,您通过AsEnumerable
调用来请求实体,指示Linq从数据库上下文切换到内存上下文。因此,当您要求计数时,Linq必须先从数据库 中获取记录,然后再对它们进行计数。
如果您在第一个示例中实际使用实体,则数据库查询将非常相似(可能不包括未使用的列,该列可以忽略不计)。如果您只需要计数,则无需使用 any 构造函数。
一个简单的测试,看看枚举第一个示例会生成什么查询,将输出更改为:
Console.WriteLine(tests.AsEnumerable().Count());
答案 2 :(得分:0)
您要解决的问题似乎已经解决了。
假设:
var tests = new MyDbContext()
.LdbRecords
.Select(r => new LdbRecord());
您将获得一个LdbRecord的IQueryable,并通过调用.ToList()这些数据库模型的列表以及其所有属性来获取。
然后您应该使用诸如AutoMapper之类的东西。接下来的逻辑将是这样的:
var results = Mapper.Map<TestClass>(tests.ToList());
您可以将AutoMapper配置为与属性名称匹配,但也可以将属性配置为忽略,或与1到1匹配。
var mapper = config.CreateMapper<LdbRecord, TestClass>();
mapper.ForMember(dest => dest.TestId, opt => opt.MapFrom(src => src.Id));
这可确保您的代码编写一次(无需遍历代码库即可将参数更改为构造函数。
此外,您可以强制AutoMapper为未映射的属性引发异常。如果仅靠AutoMapper来实现TestClass.Id和LdbRecords.Id还不够好,则该应用程序将无法构建/运行(在这里单元测试也是理想的选择)。