与LINQ和亚音速对象映射(Object mapping with LINQ and SubSoni

2019-08-31 07:42发布

我建立亚音速3.0.0.3 ActiveRecord的一个小项目,我遇到一个问题,我似乎无法让过去。

下面是LINQ查询:

var result = from r in Release.All()
             let i = Install.All().Count(x => x.ReleaseId == r.Id)
             where r.ProductId == productId
             select new ReleaseInfo
             {
                 NumberOfInstalls = i,
                 Release = new Release
                 {
                     Id = r.Id,
                     ProductId = r.ProductId,
                     ReleaseNumber = r.ReleaseNumber,
                     RevisionNumber = r.RevisionNumber,
                     ReleaseDate = r.ReleaseDate,
                     ReleasedBy = r.ReleasedBy
                 }
             };

该ReleaseInfo对象是自定义类,看起来像这样:

public class ReleaseInfo
{
    public Release Release { get; set; }
    public int NumberOfInstalls { get; set; }
}

释放和安装是由亚音速生成的类。

当我做了手表上的结果,释放属性为null。

如果我有这样的一个简单的查询和观测结果,该值不为空。

var result = from r in Release.All()
             let i = Install.All().Count(x => x.ReleaseId == r.Id)
             where r.ProductId == productId
             select new Release
             {
                 Id = r.Id,
                 ProductId = r.ProductId,
                 ReleaseNumber = r.ReleaseNumber,
                 RevisionNumber = r.RevisionNumber,
                 ReleaseDate = r.ReleaseDate,
                 ReleasedBy = r.ReleasedBy
             };

这是我的LINQ查询或亚音速的限制的问题吗?

Answer 1:

我认为这个问题可能是你基本上复制ORM的功能。 了解事情的关键是这一行:

from r in Release.All()

这条线在你的数据库中的每个项目返回的完全填充的发行记录列表。 应该永远是一个需要在查询新了释放其他地方 - 只是返回亚音速已经为您填充了的!

使用这个逻辑,你应该能够做到以下几点:

 var result = from r in Release.All()
              select new ReleaseInfo {
                  Release = r,
                  NumberOfInstalls = Install.All().Count(x => x.ReleaseId == r.Id)
              };

话虽这么说,你应该看看Install.All()调用,因为这很可能是极大的效率低下。 什么,将要做的就是每天拉从数据库安装,滋润那些安装到目标,然后比较每条记录的ID在.NET来检查记录满足这一条件。 您可以使用亚音速.Find方法只在数据库层,这将有助于表现显著返回某些记录。 即便如此,充气物体仍然可能是昂贵的,你可能要考虑在此处查看或存储过程。 但作为一个简单的第一步,下面应该工作:

var result = from r in Release.All()
             select new ReleaseInfo {
                 Release = r,
                 NumberOfInstalls = Install.Find(x => x.ReleaseId == r.Id).Count()
             };


Answer 2:

我想我已经找到了答案实际这个问题。 我一直在四处翻找在亚音速源发现,有两种类型的对象投影所映射的DataReader对象时:一个用于匿名类型和分组,一个用于一切:

这里是一个片段:行269 - 298 SubSonic.Linq.Structure.DbQueryProvider的

IEnumerable<T> result;
Type type = typeof (T);
//this is so hacky - the issue is that the Projector below uses Expression.Convert, which is a bottleneck
//it's about 10x slower than our ToEnumerable. Our ToEnumerable, however, stumbles on Anon types and groupings
//since it doesn't know how to instantiate them (I tried - not smart enough). So we do some trickery here.
    if (type.Name.Contains("AnonymousType") || type.Name.StartsWith("Grouping`") || type.FullName.StartsWith("System.")) {
    var reader = _provider.ExecuteReader(cmd);
    result = Project(reader, query.Projector);
    } else
    {
        using (var reader = _provider.ExecuteReader(cmd))
        {
            //use our reader stuff
            //thanks to Pascal LaCroix for the help here...
            var resultType = typeof (T);
            if (resultType.IsValueType)
            {
                result = reader.ToEnumerableValueType<T>();
            }
            else
            {
                result = reader.ToEnumerable<T>();
            }
        }
    }
    return result;

原来,亚音速ToEnumerable试图在DataReader的到对象你要投射到属性相匹配的列名。 从我的LINQ SQL查询看起来是这样的:

SELECT [t0].[Id], [t0].[ProductId], [t0].[ReleaseDate], [t0].[ReleasedBy], [t0].[ReleaseNumber], [t0].[RevisionNumber], [t0].[c0]
FROM (
  SELECT [t1].[Id], [t1].[ProductId], [t1].[ReleaseDate], [t1].[ReleasedBy], [t1].[ReleaseNumber], [t1].[RevisionNumber], (
    SELECT COUNT(*)
    FROM [dbo].[Install] AS t2
    WHERE ([t2].[ReleaseId] = [t1].[Id])
    ) AS c0
  FROM [dbo].[Release] AS t1
  ) AS t0
WHERE ([t0].[ProductId] = 2)

注意[T 0] [C0]是不一样的我的属性名称NumberOfInstalls。 所以C0的值永远不会被投射到我的对象。

解决方法:你可以简单地取出if语句,并使用慢10倍的投影,一切都将正常工作。



Answer 3:

我们有某些occassions该车次的预测中的错误 - 我认为它经过修补,但我需要更多的测试。 我邀请您来尝试最新位 - 我认为我们已经固定它...很抱歉说得这么含糊,但错误的工作它的方式在3.0.0.1和3.0.0.3之间,我一直没能找到它。



Answer 4:

这已经被固定在3.0.0.4? 我很气恼找到这篇文章。 之后的试图找出为什么我的预测是不工作2天 - 除了当属性名称完全匹配查询 - 我在这里结束了。 我是如此依赖于SS SimpleRepository,这是为时已晚,现在回头。 像这样的错误是沉重的。 任何机会,它整理出来?

我去的要慢10倍路线,所以我现在至少可以释放我的客户。 更希望更快的方法才能正常工作:)



文章来源: Object mapping with LINQ and SubSonic