流利的Nhibernate生成错误的查询导致笛卡尔积而不是单行

时间:2018-03-18 15:13:56

标签: nhibernate orm fluent-nhibernate

在尝试了很多东西之后,我仍然无法找到使用Fluent NHibernate查询以下关系的正确方法。 如果我不得不编写SQL查询,那么这将是一个更容易的任务。希望得到一些更好的建议,以避免N + 1问题和未经优化的自动生成的SQL查询。

我有以下关系,如下所示:

标签可以包含与之相关的媒体内容(各种预定义大小的图像,视频,文档等)   - 1个标签可以映射多个媒体项目(让我们说尺寸为32x32,64x64,600x100,0或更多视频的图像)
  - 每个媒体项目都映射到媒体描述,这有助于识别媒体的大小和类型   - 相同的媒体项可以由不同的标签使用。例如,所有标签都没有任何图标的通用图像。

ERD for your reference

实体:
媒体

public class Media:IEntity
{
        private ICollection<TagMedia> _tagMedia;  

        public virtual int Id { get; set; }
        public virtual string FilePath { get; set; }
        public virtual MediaType MediaType { get; set; }
        public virtual ICollection<TagMedia> TagMedia
        {
            get { return _tagMedia?? (_tagMedia= new List<TagMedia>()); }
            protected set { _tagMedia= value; }
        }
}

标签

public class Tag:IEntity
    {
        private ICollection<TagMedia> _tagMedia;
        public virtual int Id { get; set; }
        public virtual string Name { get; set; }
        public virtual ICollection<TagMedia> TagMedia
        {
            get { return _tagMedia?? (_tagMedia= new List<TagMedia>()); }
            set { _tagMedia= value; }
        }
}

TagMedia

public class TagMedia :IEntity
{
        public virtual int Id { get; set; }
        public virtual Media Media { get; set; }
        public virtual Tag Tag { get; set; }

        public virtual DateTime AddedOn { get; set; }
}

MediaType

public class MediaType:IEntity
{
        public virtual int Id { get; set; }
        public virtual string Description { get; set; }
}

映射

MediaMapping

public class MediaMapping : IAutoMappingOverride<Media>
{
    public void Override(AutoMapping<Media> mapping)
    {
         mapping.Map(c => c.FileName).CustomSqlType("varchar(60)").Not.Nullable();  
    }
}

TagMapping

public class TagMapping : IAutoMappingOverride<Tag>
    {
        public void Override(AutoMapping<Tag> mapping)
        {
            mapping.HasMany<TagMedia>(c => c.TagMedia)
                .KeyColumn("TagId")
                .Cascade.SaveUpdate()
                .BatchSize(25);

            mapping.BatchSize(25);
            mapping.DynamicUpdate();
            mapping.DynamicInsert();
        }
    }

TagMediaMapping

public class TagMediaMapping : IAutoMappingOverride<TagMedia>
    {
        public void Override(AutoMapping<TagMedia> mapping)
        {
            mapping.Map(c=>c.AddedOn);
        }
    }

查询:
以下查询获取映射到标记的所有媒体的笛卡尔积,并且不会消除&#34; Icon-16x16&#34;以外的记录。我希望ORM返回不超过一行。

任何帮助都将受到高度赞赏。

_session.Query<Tag>()
                .FetchMany(x => x.TagMedia)
                .ThenFetch(x => x.Media)
                .ThenFetch(x=>x.MediaType)
                .Where(c => c.Id == id 
                        && c.TaxonomyMedia.Any(x=>x.Media.MediaType.Description== "Icon-16x16")) 
                .SingleOrDefault();

生成的SQL:

exec sp_executesql N'select * 
from [Tag] Tag0_ left outer join [TagMedia] Tagme1_ on Tag0_.TagId=Tagme1_.TagId 
left outer join [Media] media2_ on Tagme1_.MediaId=media2_.MediaId 
left outer join [MediaType] mediatype3_ on media2_.MediaTypeId=mediatype3_.MediaTypeId 
where Tag0_.TagId=@p0 
and (exists (select Tagme4_.TagMediaId 
                    from [TagMedia] Tagme4_ inner join [Media] media5_ on Tagme4_.MediaId=media5_.MediaId inner join [MediaType] mediatype6_ on media5_.MediaTypeId=mediatype6_.MediaTypeId where Tag0_.TagId=Tagme4_.TagId and mediatype6_.MediaTypeDescription=@p1))',N'@p0 int,@p1 nvarchar(4000)',@p0=102,@p1=N'Icon-16x16'
go

1 个答案:

答案 0 :(得分:0)

SingleOrDefault函数是一个LINQ函数,NHibernate没有实现。使用。取(1) 我认为解决方案是:

_session.Query<Tag>()
            .FetchMany(x => x.TagMedia)
            .ThenFetch(x => x.Media)
            .ThenFetch(x=>x.MediaType)
            .Where(c => c.Id == id 
                    && c.TaxonomyMedia.Any(x=>x.Media.MediaType.Description== "Icon-16x16")) 
            .Take(1)
            .SingleOrDefault();