亚音速3.0和LINQ(Subsonic 3.0 and linq)

2019-09-03 05:25发布

我亚音速3.0 SimpleRepository玩耍,并试图让菜单和的菜单项与一个LINQ查询,但的菜单项是空永诺

菜单

public class Menu
{
    public Menu()
    {
        MenuId = 0;
        MenuName = "";
        MenuItems = null;
    }
    public int MenuId { get; set; }
    public string MenuName { get; set; }
    public MenuItem MenuItems { get; set; }
}

菜单项

public class MenuItem
{
    public MenuItem()
    {
        MenuItemId = 0;
        MenuId = 0;
        MenuItemName = "";
    }
    public int MenuItemId { get; set; }
    public int MenuId { get; set; }
    public string MenuItemName { get; set; }
}

LINQ查询

var menus =  from m in _repo.All<Menu>()
             from mi in _repo.All<MenuItem>()
             where m.MenuItems.MenuItemId == mi.MenuItemId
             select new Menu
             {
                 MenuId = m.MenuId,
                 MenuName = m.MenuName,
                 MenuItems = {
                             MenuItemId = mi.MenuItemId,
                             MenuItemName = mi.MenuItemName
                        }
             };

可有一个人告诉我,我究竟做错了什么?

Answer 1:

我想我已经找到了答案实际这个问题。 我一直在四处翻找在亚音速源发现,有两种类型的对象投影所映射的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 2:

我不认为你在这里做什么错事。 这似乎是亚音速3.0中的问题。 我有它的问题,现在,我还没有得到一个答案在这里 。 我也最近想简单的东西。 但是,这不工作要么。

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,
                 Id = r.Id,
                 ProductId = r.ProductId,
                 ReleaseNumber = r.ReleaseNumber,
                 RevisionNumber = r.RevisionNumber,
                 ReleaseDate = r.ReleaseDate,
                 ReleasedBy = r.ReleasedBy
             };

已安装财产数量没有得到填充,但如果我映射到一个匿名类型一切正常:

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

如果你改变你的代码如下它可能会工作:

var menus =  from m in _repo.All<Menu>()
             from mi in _repo.All<MenuItem>()
             where m.MenuItems.MenuItemId == mi.MenuItemId
             select new 
             {
                 MenuId = m.MenuId,
                 MenuName = m.MenuName,
                 MenuItems = new {
                             MenuItemId = mi.MenuItemId,
                             MenuItemName = mi.MenuItemName
                        }
             };

这种失败的目的,因为要映射回预定义的对象类型。 也许我们可以从罗布这个答案吗? :)



文章来源: Subsonic 3.0 and linq