0

是否可以在 NHibernate 中映射一个使用迭代器的只读属性(即,yield return)?

例如,假设我们有一个Person具有只读IEnumerable<Cat> Cats属性的类和一个调用的方法,该方法GetNextCat()可以获取序列中的下一只猫。

这是可能的映射:

public class PersonMap : ClassMap<Person>
{
    public PersonMap()
    {
        HasMany(x => x.Cats).Access.ReadOnly(); // also tried .AsSet() and .AsBag()
    }
}

以下是该属性的两种可能实现IEnumerable<Cat> Cats

// fails: 
//   System.InvalidCastException: Unable to cast object of type '<get_Cats>d__0' to 
//   type 'System.Collections.Generic.ICollection`1[MyProject.Cat]'.
public virtual IEnumerable<Cat> Cats
{
    get
    {
        var cat = GetNextCat();

        while(cat != null)
        {
            yield return cat;
            cat = GetNextCat();
        }

        yield break;
    }
}

// works
public virtual IEnumerable<Cat> Cats
{
    get
    {
        var catList = new List<Cat>();
        var cat = GetNextCat();

        while(cat != null)
        {
            catList.Add(cat);
            cat = GetNextCat();
        }

        return catList;
    }
}

两个版本的属性产生相同的结果。那么,为什么 NHibernate 与第一个示例不同,而与第二个示例一起使用呢?是不是 NHibernate 只是没有设置来处理编译器生成的类yield return?或者这只是 Fluent 的问题?

4

1 回答 1

1

属性的结果是不同的。

第一个生成一个生成的 IEnumerable(迭代器),第二个返回一个生成的列表。NHibernate 尝试将 ICollection/ISet/Ilist(取决于 AsBag/Set/List)包装在一个对 IEnumerable 失败而对 List 成功的 persistentBag/Set/List 中。

然而,两者都是不正确的,因为 NHibernate 无法动态更改生成的对象的轨道,因此第二个代码将运行但会产生疯狂的结果和/或异常。

结论:根本不要映射这个属性,因为它是在代码中生成的,而不是从数据库中加载的。加载/映射GetNextCat()用于获取下一只猫的持久数据。

于 2013-07-26T07:25:05.003 回答