Богатая расширяемая модель домена с беглым nhibernate - PullRequest
0 голосов
/ 29 июня 2011

Я играю с nhibernate и fluent-nhibernate.

Что я хочу сделать, это создать базу с базовыми моделями / сущностями, а затем иметь возможность создавать плагин, который работает с базой и / илирасширяет базу.Если я болтаю, надеюсь, это будет понятно по примерам кода.

У меня есть сборка, которая действует как мой краеугольный камень (базовая сборка). Здесь я получил сущность:

public class MemberBase
    {
        public virtual Guid Id { get; set; }
        public virtual string UserName { get; set; }
        public virtual string Password { get; set; }
        public virtual string FirstName { get; set; }
        public virtual string LastName { get; set; }
    }

И я получил мое свободное отображение:

public MemberBaseMap()
        {
            Id(x => x.Id);
            Map(x => x.UserName);
            Map(x => x.Password);
            Map(x => x.FirstName);
            Map(x => x.LastName);
            Table("Members");
        }

Я получил свой интерфейс для репозитория участников:

public interface IMemberBaseRepository<T>
    {
        void Add(T m);
        void Update(T m);
        void Remove(T m);

        T Fetch(Guid id);
        ICollection<T> List { get; }
    }

И я даже получил свой основной репозиторий для участников:

public class MemberBaseRepository : IMemberBaseRepository<MemberBase>
    {
        private static ISessionFactory _sessionFactory;
        private static ISessionFactory SessionFactory
        {
            get
            {
                if (_sessionFactory == null)
                    _sessionFactory = Fluently.Configure()
                        .Database(MsSqlConfiguration.MsSql2008.ShowSql().ConnectionString("Data Source=W7;Initial Catalog=nhibernateDemo;Integrated Security=True"))
                        .Mappings(m => m.FluentMappings.AddFromAssemblyOf<MemberBase>()
                            //.Conventions.Add(Table.Is(x => "Members"))
                            )
                        //.ExposeConfiguration(BuildSchema)
                        .BuildSessionFactory();
                return _sessionFactory;
            }
        }

        public void Add(MemberBase m)
        {
            using (ISession session = SessionFactory.OpenSession())
            using (ITransaction transaction = session.BeginTransaction())
            {
                session.Save(m);
                transaction.Commit();
            }
        }

        public void Update(MemberBase m)
        {
            using (ISession session = SessionFactory.OpenSession())
            using (ITransaction transaction = session.BeginTransaction())
            {
                session.Update(m);
                transaction.Commit();
            }
        }

        public void Remove(MemberBase m)
        {
            using (ISession session = SessionFactory.OpenSession())
            using (ITransaction transaction = session.BeginTransaction())
            {
                session.Delete(m);
                transaction.Commit();
            }
        }

        public MemberBase Fetch(Guid id)
        {
            using (ISession session = SessionFactory.OpenSession())
                return session.Get<MemberBase>(id);
        }

        public ICollection<MemberBase> List
        {
            get
            {
                using (ISession session = SessionFactory.OpenSession())
                    return session.CreateCriteria(typeof(MemberBase)).List<MemberBase>();
            }
        }
    }

Все это работает в моем тестировании, без проблем: Вот мое тестирование nunit:

[TestFixture]
    public class MembersBasic
    {
        private ISessionFactory _sessionFactory;
        private FluentConfiguration _configuration;
        private IMemberBaseRepository<MemberBase> _repository;

        private IMemberBaseRepository<MemberBase> Repository
        {
            get
            {
                if (_repository == null)
                    _repository = new MemberBaseRepository();
                return _repository;
            }
        }

        #region Test Data
        private readonly MemberBase[] _members = new[]
            {
                new MemberBase { FirstName = "Daisy", LastName = "Harrison" },
                new MemberBase { FirstName = "Jack", LastName = "Torrance" },
                new MemberBase { FirstName = "Sue", LastName = "Wilkters" },
                new MemberBase { FirstName = "Bill", LastName = "Taft" },
                new MemberBase { FirstName = "Joan", LastName = "Pope" }
            };
        private void CreateInitialData()
        {
            using (ISession session = _sessionFactory.OpenSession())
            {
                using (ITransaction transaction = session.BeginTransaction())
                {
                    foreach (var m in _members)
                        session.Save(m);
                    transaction.Commit();
                }
            }
        }
        #endregion

        private bool IsInCollection(MemberBase m, ICollection<MemberBase> collection)
        {
            foreach (var item in collection)
                if (m.Id == item.Id)
                    return true;
            return false;
        }

        //[TestFixtureSetUp]
        //public void TestFixtureSetup()
        //{
        //}

        [SetUp]
        public void Setup()
        {
            _configuration = Fluently.Configure()
                .Database(MsSqlConfiguration.MsSql2008.ShowSql().ConnectionString("Data Source=localhost;Initial Catalog=nhibernateDemo;Integrated Security=True"))
                .Mappings(m => m.FluentMappings.AddFromAssemblyOf<MemberBase>()
                    //.Conventions.Add(Table.Is(x=> "Members"))
                )
                .ExposeConfiguration(cfg =>
                {
                    new SchemaExport(cfg).Create(false, true);
                });
            _sessionFactory = _configuration.BuildSessionFactory();
            CreateInitialData();
        }

        [Test]
        public void Can_add_member()
        {
            var member = new MemberBase { FirstName = "John", LastName = "Doe" };
            Repository.Add(member);

            using (ISession session = _sessionFactory.OpenSession())
            {
                var fromDB = session.Get<MemberBase>(member.Id);
                Assert.IsNotNull(fromDB);
                Assert.AreNotSame(member, fromDB);
                Assert.AreEqual(member.FirstName, fromDB.FirstName);
                Assert.AreEqual(member.LastName, fromDB.LastName);
            }
        }

        [Test]
        public void Can_update_member()
        {
            var member = _members[0];
            member.FirstName = "John";
            member.LastName = "Doe";

            Repository.Update(member);

            using (ISession session = _sessionFactory.OpenSession())
            {
                var fromDB = session.Get<MemberBase>(member.Id);
                Assert.AreEqual(member.FirstName, fromDB.FirstName);
                Assert.AreEqual(member.LastName, fromDB.LastName);
            }
        }

        [Test]
        public void Can_remove_member()
        {
            Repository.Remove(_members[0]);

            using (ISession session = _sessionFactory.OpenSession())
            {
                var fromDB = session.Get<MemberBase>(_members[0].Id);
                Assert.IsNull(fromDB);
            }
        }

        [Test]
        public void Can_fetch_member()
        {
            var member = Repository.Fetch(_members[0].Id);
            Assert.IsNotNull(member);
            Assert.AreEqual(_members[0].Id, member.Id);
            Assert.AreEqual(_members[0].FirstName, member.FirstName);
            Assert.AreEqual(_members[0].LastName, member.LastName);
        }

        [Test]
        public void Can_list_members()
        {
            var members = Repository.List;
            Assert.IsNotNull(members);
            Assert.AreEqual(5, members.Count);
            Assert.IsTrue(IsInCollection(_members[0], members));
            Assert.IsTrue(IsInCollection(_members[1], members));
            Assert.IsTrue(IsInCollection(_members[2], members));
            Assert.IsTrue(IsInCollection(_members[3], members));
            Assert.IsTrue(IsInCollection(_members[4], members));
        }
    }

Теперь, когда все мои проблемы начинаются, когда я сейчас в новой сборке создаю элемент, который наследует базуи получает его картограф и так далее, и свой собственный репозиторий.Вот расширенный материал:

public class MemberExt : MemberBase
    {
        public virtual string Email { get; set; }
    }
public class MemberExtMap : SubclassMap<MemberExt>
    {
        public MemberExtMap()
        {
            Extends<MemberBase>();
            Map(x => x.Email);
            Table("Members");
        }
    }
public class MemberExtRepository : IMemberBaseRepository<MemberExt>
    {
        private static ISessionFactory _sessionFactory;
        private static ISessionFactory SessionFactory
        {
            get
            {
                if (_sessionFactory == null)
                    _sessionFactory = Fluently.Configure()
                        .Database(MsSqlConfiguration.MsSql2008.ShowSql().ConnectionString("Data Source=W7;Initial Catalog=nhibernateDemo;Integrated Security=True"))
                        .Mappings(m => m.FluentMappings.AddFromAssemblyOf<MemberExt>()
                            //.Conventions.Add(Table.Is(x => "Members"))
                            )
                        //.ExposeConfiguration(BuildSchema)
                        .BuildSessionFactory();
                return _sessionFactory;
            }
        }

        public void Add(MemberExt m)
        {
            using (ISession session = SessionFactory.OpenSession())
            using (ITransaction transaction = session.BeginTransaction())
            {
                session.Save(m);
                transaction.Commit();
            }
        }

        public void Update(MemberExt m)
        {
            using (ISession session = SessionFactory.OpenSession())
            using (ITransaction transaction = session.BeginTransaction())
            {
                session.Update(m);
                transaction.Commit();
            }
        }

        public void Remove(MemberExt m)
        {
            using (ISession session = SessionFactory.OpenSession())
            using (ITransaction transaction = session.BeginTransaction())
            {
                session.Delete(m);
                transaction.Commit();
            }
        }

        public MemberExt Fetch(Guid id)
        {
            using (ISession session = SessionFactory.OpenSession())
                return session.Get<MemberExt>(id);
        }

        public ICollection<MemberExt> List
        {
            get
            {
                using (ISession session = SessionFactory.OpenSession())
                    return session.CreateCriteria(typeof(MemberExt)).List<MemberExt>();
            }
        }
    }

Ну, это должно работать, я думаю, и, возможно, это работает, но когда я пытаюсь запустить мою настройку теста, я получаю ошибку:

"Test.Extend.Members.MembersExt.Can_add_member: SetUp: NHibernate.MappingException: не сохраняется для: Plugin.Ext.Entity.MemberExt "

Редактировать

ПолученоПохоже, что моя ошибка была в том, что мне нужно было иметь другую таблицу для моего подкласса, и здесь были сохранены только расширенные свойства.Или при использовании DiscriminateSubClassesOnColumn ("Тип") я получил все это в одной таблице.Я также должен был отобразить базовый класс при отображении моего подкласса при создании фабрики сеансов.

Можно ли сказать, что у меня будут только экземпляры расширенного класса, и я сохраню все данные в одной таблице без DisciminateSubClassesOnColumn ?

Редактировать 2

Получил работу, как я хотел, используя UseUnionSubclassForInheritanceMapping (); я получаюбазовый класс работает, как я хочу, и даже если я добавлю расширенный объект и тем самым расширю мою базу данных с помощью дополнительного поля электронной почты, я все равно смогу получить все экземпляры как базовый объект и даже получить все экземпляры как расширенный класс.

...