Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/wpf/12.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Wpf NHibernate和奇怪的铸造例外_Wpf_Data Binding_Nhibernate - Fatal编程技术网

Wpf NHibernate和奇怪的铸造例外

Wpf NHibernate和奇怪的铸造例外,wpf,data-binding,nhibernate,Wpf,Data Binding,Nhibernate,第二天我就要和它战斗了,我受够了 我的UI出现了奇怪的异常 第一件事。 我的模型基本上是这样的: - Document - Period 1 - Sheet 1 基类: public class DbItem: ObservableModel { public virtual Document ParentDocument { get; set; } Guid id; public virtual Guid Id { get { r

第二天我就要和它战斗了,我受够了

我的UI出现了奇怪的异常

第一件事。 我的模型基本上是这样的:

- Document
  - Period 1
    - Sheet 1
基类:

public class DbItem: ObservableModel
{
    public virtual Document ParentDocument { get; set; }

    Guid id;
    public virtual Guid Id
    {
        get { return id; }
        set
        {
            if (id != value)
            {
                id = value;
                NotifyPropertyChanged();
            }
        }
    }

    string name = string.Empty;
    public virtual string Name
    {
        get { return name; }
        set
        {
            if (value == null || name != value)
            {
                name = value;
                NotifyPropertyChanged();
            }
        }
    }

}
public enum PeriodType
{
    Year,
    Sheet
}

public abstract class PeriodBase : DbItem
{
    public virtual Period ParentPeriod { get; set; }
    public virtual PeriodType PeriodType { get; set; }
}
接下来是基类:

public class DbItem: ObservableModel
{
    public virtual Document ParentDocument { get; set; }

    Guid id;
    public virtual Guid Id
    {
        get { return id; }
        set
        {
            if (id != value)
            {
                id = value;
                NotifyPropertyChanged();
            }
        }
    }

    string name = string.Empty;
    public virtual string Name
    {
        get { return name; }
        set
        {
            if (value == null || name != value)
            {
                name = value;
                NotifyPropertyChanged();
            }
        }
    }

}
public enum PeriodType
{
    Year,
    Sheet
}

public abstract class PeriodBase : DbItem
{
    public virtual Period ParentPeriod { get; set; }
    public virtual PeriodType PeriodType { get; set; }
}
还有一些属性,但为了清晰起见,我只是在这里删除了它们

接下来,我们有一个从PeriodBase继承的Period类:

public class Period : PeriodBase
{
    IList<PeriodBase> periods = new ObservableCollection<PeriodBase>();
    public virtual IList<PeriodBase> Periods
    {
        get { return periods; }
        set
        {
            if (periods != value)
            {
                periods = value;
                NotifyPropertyChanged();
            }
        }
    }
}
public class Sheet : PeriodBase
{
    DateTimeOffset startDate;
    public override DateTimeOffset StartDate
    {
        get { return startDate; }
        set
        {
            if (startDate != value)
            {
                startDate = value;
                NotifyPropertyChanged();
            }
        }
    }

    DateTimeOffset endDate;
    public override DateTimeOffset EndDate
    {
        get { return endDate; }
        set
        {
            if (endDate != value)
            {
                endDate = value;
                NotifyPropertyChanged();
            }
        }
    }
}
最后是document类,它由句点组成:

public class Document: DbItem
{
    IList<Period> periods = new ObservableCollection<Period>();
    public virtual IList<Period> Periods
    {
        get { return periods; }
        set
        {
            if (periods != value)
            {
                periods = value;
                NotifyPropertyChanged();
            }
        }
    }
}
我的绑定如下所示:

public class DocumentMap : DbItemMap<Document>
{
    public DocumentMap()
    {
        Table("documents");
        HasMany(x => x.Periods).ForeignKeyConstraintName("ParentDocument_id");
    }
}


public class PeriodBaseMap: DbItemMap<PeriodBase>
{
    public PeriodBaseMap()
    {
        UseUnionSubclassForInheritanceMapping();
        References(x => x.ParentPeriod);
        Map(x => x.Name).Not.Nullable();
        Map(x => x.PeriodType).CustomType<PeriodType>();
    }
}

public class PeriodMap : SubclassMap<Period>
{
    public PeriodMap()
    {
        Table("periods");
        Abstract();
        References(x => x.ParentDocument);
        HasMany(x => x.Periods).Inverse().Not.LazyLoad();
    }
}

public class SheetMap : SubclassMap<Sheet>
{
    public SheetMap()
    {
        Table("sheets");
        Abstract();
        Map(x => x.StartDate);
        Map(x => x.EndDate);
    }
}
重要的是,在启动应用程序并加载文档并单击treeview中的扩展器以展开期间后,我会遇到相同的错误。但是当我第一次运行应用程序时,一切都正常,直到我保存了文档

有什么问题吗

回复马克·费尔德曼的帖子

我决定回答,因为这太长了,无法评论。这是我第一次见到ORM,所以我可能对此有一些错误的想法。我的解决方案中只有一个模型。通常(使用SQL)它会工作。我将获取一个对象,将其插入到DB中,另一种方法也是如此

所以我在这里也是这么做的。我只有一个商业模式,它有一些简单的商业规则。它在ViewModels中使用,并存储在db中。这是一个糟糕的解决方案吗?我应该有另一个模式和一些打破干涸的原则

在我的脑海中,假设它是这样工作的:用户单击“创建新工作表”。这是(这是从命令调用的我的ViewModel->方法的一部分):

ModifiedItems只是一个保存已修改项的字典。由于这一点,我不必保存整个文档,只需修改项目即可


据我所知,这不是应该的。那么正确的方法是什么呢?或者ORM不适合这里?

除非在我使用它之后的几年中NHibernate发生了重大变化,否则您不能仅仅从ObservaleModel派生模型类并期望它工作。看来,您的理由是将INPC赋予DB模型,有些人会认为这不是很好的关注点分离,并表明您的视图模型层设计不正确

也就是说,如果你真的坚持要这样做,那么不要从ObservaleModel中派生实体,而是尝试在NHibernate首次创建实体时使用Castle Dynamic Proxy之类的工具将INPC注入实体。Ayende Rahien的帖子展示了如何做到这一点,并提供了您需要的代码

您将面临的下一个问题是集合问题。同样,您不能只将
observateCollection
分配给
IList
属性并期望它工作,NHibernate在反序列化集合时会替换整个列表,而不是对已分配的现有集合使用“添加/删除”。加载列表后,可以使用
ObserveableCollection
替换列表,但如果这样做,则无论是否更改,NHibernate都会认为整个列表已更改,并再次序列化整个列表。一开始你会侥幸逃脱的,但很快你的表演就会开始受到伤害

要解决这个问题,您必须使用约定,以便NHibernate创建支持INotifyCollectionChanged的集合实体。不幸的是,我最初读到的关于这一点的页面早就消失了,所以我只能在这里发布代码(遗憾的是没有归属)。我只在NHibernate Fluent中使用了约定,所以我将让您了解如何在您自己的案例中应用它们,但以下是您需要的

public class ObservableBagConvention : ICollectionConvention
{
    public void Apply(ICollectionInstance instance)
    {
        Type collectionType = typeof(ObservableBagType<>)
            .MakeGenericType(instance.ChildType);
        instance.CollectionType(collectionType);
        instance.LazyLoad();            
    }
}

public class ObservableBagType<T> : CollectionType, IUserCollectionType
{
    public ObservableBagType(string role, string foreignKeyPropertyName, bool isEmbeddedInXML)
        : base(role, foreignKeyPropertyName, isEmbeddedInXML)
    {
    }

    public ObservableBagType()
        : base(string.Empty, string.Empty, false)
    {

    }
    public IPersistentCollection Instantiate(ISessionImplementor session, ICollectionPersister persister)
    {
        return new PersistentObservableGenericBag<T>(session);
    }

    public override IPersistentCollection Instantiate(ISessionImplementor session, ICollectionPersister persister, object key)
    {
        return new PersistentObservableGenericBag<T>(session);
    }

    public override IPersistentCollection Wrap(ISessionImplementor session, object collection)
    {
        return new PersistentObservableGenericBag<T>(session, (ICollection<T>)collection);
    }

    public IEnumerable GetElements(object collection)
    {
        return ((IEnumerable)collection);
    }

    public bool Contains(object collection, object entity)
    {
        return ((ICollection<T>)collection).Contains((T)entity);
    }

    protected override void Clear(object collection)
    {
        ((IList)collection).Clear();
    }

    public object ReplaceElements(object original, object target, ICollectionPersister persister, object owner, IDictionary copyCache, ISessionImplementor session)
    {
        var result = (ICollection<T>)target;
        result.Clear();
        foreach (var item in ((IEnumerable)original))
        {
            if (copyCache.Contains(item))
                result.Add((T)copyCache[item]);
            else
                result.Add((T)item);
        }
        return result;
    }

    public override object Instantiate(int anticipatedSize)
    {
        return new ObservableCollection<T>();
    }

    public override Type ReturnedClass
    {
        get
        {
            return typeof(PersistentObservableGenericBag<T>);
        }
    }
}
公共类observebagconvention:ICollectionConvention
{
public void Apply(ICollectionInstance实例)
{
类型collectionType=typeof(ObservableBagType)
.MakeGenericType(实例.ChildType);
实例.CollectionType(CollectionType);
instance.LazyLoad();
}
}
公共类observebagtype:CollectionType、IUserCollectionType
{
公共ObservableBagType(字符串角色、字符串foreignKeyPropertyName、布尔isEmbeddedInXML)
:base(角色、foreignKeyPropertyName、isEmbeddedInXML)
{
}
public observebagtype()
:base(string.Empty,string.Empty,false)
{
}
公共IPersistentCollection实例化(ISessionImplementor会话,ICollectionPersister persister)
{
返回新的PersistentObservableGenericBag(会话);
}
公共重写IPersistentCollection实例化(ISessionImplementor会话、ICollectionPersister持久化器、对象键)
{
返回新的PersistentObservableGenericBag(会话);
}
公共覆盖IPersistentCollection包装(ISessionImplementor会话,对象集合)
{
返回新的PersistentObservableGenericBag(会话,(ICollection)集合);
}
公共IEnumerable GetElements(对象集合)
{
返回((IEnumerable)集合);
}
公共布尔包含(对象集合、对象实体)
{
返回((ICollection)集合)。包含((T)实体);
}
受保护的替代无效清除(对象集合)
{
((IList)集合)。清除();
}
公共对象替换元素(对象原始、对象目标、ICollectionPersister持久器、对象所有者、IDictionary copyCache、ISessionImplementor会话)
{
var结果=(ICollection)目标;
result.Clear();
foreach(原始(IEnumerable)中的var项目)
{
if(copyCache.Contains(项))
添加((T)copyCache[项]);
其他的
结果。添加((T)项);
}
返回结果;
}
公共重写对象实例化(int expectedsize)
{
返回新的ObservableCollection();
}
公共重写类型ReturnedClass
{
得到
{
返回
async Task SaveDocument(Document doc)
{
    foreach(var item in doc.ModifiedItems)
      db.SaveOrUpdate(item);
}
public class ObservableBagConvention : ICollectionConvention
{
    public void Apply(ICollectionInstance instance)
    {
        Type collectionType = typeof(ObservableBagType<>)
            .MakeGenericType(instance.ChildType);
        instance.CollectionType(collectionType);
        instance.LazyLoad();            
    }
}

public class ObservableBagType<T> : CollectionType, IUserCollectionType
{
    public ObservableBagType(string role, string foreignKeyPropertyName, bool isEmbeddedInXML)
        : base(role, foreignKeyPropertyName, isEmbeddedInXML)
    {
    }

    public ObservableBagType()
        : base(string.Empty, string.Empty, false)
    {

    }
    public IPersistentCollection Instantiate(ISessionImplementor session, ICollectionPersister persister)
    {
        return new PersistentObservableGenericBag<T>(session);
    }

    public override IPersistentCollection Instantiate(ISessionImplementor session, ICollectionPersister persister, object key)
    {
        return new PersistentObservableGenericBag<T>(session);
    }

    public override IPersistentCollection Wrap(ISessionImplementor session, object collection)
    {
        return new PersistentObservableGenericBag<T>(session, (ICollection<T>)collection);
    }

    public IEnumerable GetElements(object collection)
    {
        return ((IEnumerable)collection);
    }

    public bool Contains(object collection, object entity)
    {
        return ((ICollection<T>)collection).Contains((T)entity);
    }

    protected override void Clear(object collection)
    {
        ((IList)collection).Clear();
    }

    public object ReplaceElements(object original, object target, ICollectionPersister persister, object owner, IDictionary copyCache, ISessionImplementor session)
    {
        var result = (ICollection<T>)target;
        result.Clear();
        foreach (var item in ((IEnumerable)original))
        {
            if (copyCache.Contains(item))
                result.Add((T)copyCache[item]);
            else
                result.Add((T)item);
        }
        return result;
    }

    public override object Instantiate(int anticipatedSize)
    {
        return new ObservableCollection<T>();
    }

    public override Type ReturnedClass
    {
        get
        {
            return typeof(PersistentObservableGenericBag<T>);
        }
    }
}
public class PersistentObservableGenericBag<T> : PersistentGenericBag<T>, INotifyCollectionChanged,
                                                 INotifyPropertyChanged, IList<T>
{
    private NotifyCollectionChangedEventHandler _collectionChanged;
    private PropertyChangedEventHandler _propertyChanged;

    public PersistentObservableGenericBag(ISessionImplementor sessionImplementor)
        : base(sessionImplementor)
    {
    }

    public PersistentObservableGenericBag(ISessionImplementor sessionImplementor, ICollection<T> coll)
        : base(sessionImplementor, coll)
    {
        CaptureEventHandlers(coll);
    }

    public PersistentObservableGenericBag()
    {
    }

    #region INotifyCollectionChanged Members

    public event NotifyCollectionChangedEventHandler CollectionChanged
    {
        add
        {
            Initialize(false);
            _collectionChanged += value;
        }
        remove { _collectionChanged -= value; }
    }

    #endregion

    #region INotifyPropertyChanged Members

    public event PropertyChangedEventHandler PropertyChanged
    {
        add
        {
            Initialize(false);
            _propertyChanged += value;
        }
        remove { _propertyChanged += value; }
    }

    #endregion

    public override void BeforeInitialize(ICollectionPersister persister, int anticipatedSize)
    {
        base.BeforeInitialize(persister, anticipatedSize);
        CaptureEventHandlers(InternalBag);
    }

    private void CaptureEventHandlers(ICollection<T> coll)
    {
        var notificableCollection = coll as INotifyCollectionChanged;
        var propertyNotificableColl = coll as INotifyPropertyChanged;

        if (notificableCollection != null)
            notificableCollection.CollectionChanged += OnCollectionChanged;

        if (propertyNotificableColl != null)
            propertyNotificableColl.PropertyChanged += OnPropertyChanged;
    }

    private void OnPropertyChanged(object sender, PropertyChangedEventArgs e)
    {
        PropertyChangedEventHandler changed = _propertyChanged;
        if (changed != null) changed(this, e);
    }

    private void OnCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
    {
        NotifyCollectionChangedEventHandler changed = _collectionChanged;
        if (changed != null) changed(this, e);
    }
}