Свободная ошибка NHibernate: у объекта 'ClassMap`1' нет сопоставленного идентификатора - PullRequest
4 голосов
/ 11 июля 2011

Я преобразую предыдущий проект из обычного отображения NHibernate hbm.xml в Fluent NHibernate.В настоящее время я застрял на том, что должно быть одним из последних шагов, чтобы это заработало.Я добавил производный класс для DefaultAutomappingConfiguration, чтобы изменить мое соглашение об именовании идентификаторов.Строка «Id» добавляется к имени класса:

    public override bool IsId(FluentNHibernate.Member member)
    {
        return member.Name == member.DeclaringType.Name + "Id";
    }

Это должно сделать «Агентство» идентификатором в поле с именем «AgencyId».Вместо этого я получаю эту ошибку:

The entity 'ClassMap`1' doesn't have an Id mapped. Use the Id method to map your identity property. For example: Id(x => x.Id).
{Name = "ClassMap`1" FullName = "FluentNHibernate.Mapping.ClassMap`1[[BackendDb.Model.Agency, BackendDb, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]]"}

Я сделал точку останова для функции IsId, чтобы посмотреть, что происходит:

{Property: Cache}
{Name = "ClassMap`1" FullName = "FluentNHibernate.Mapping.ClassMap`1[[BackendDb.Model.Agency, BackendDb, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]]"}

Что это?Объект не то, что я создал.Каждый другой объект проходит через эту функцию нормально, и те, которые я на самом деле хотел отобразить, возвращают правильное значение.

Моя фабрика сеансов выглядит примерно так:

var cfg = new MapConfig();
return Fluently.Configure()
.Database(MsSqlConfiguration.MsSql2008
.ConnectionString(m => m.Server(@".\SqlExpress")
    .Database("{some dbname}")
    .TrustedConnection()))
.Mappings(m =>
    m.AutoMappings
        .Add(AutoMap.AssemblyOf<Agency>(cfg))
)
.BuildSessionFactory();

Досадно, кажетсячто это как-то привело к тому, что три таблицы, на которых я тестировал Fluent NHibernate в моей базе данных dev, были опорожнены .Какого черта?

Ответы [ 2 ]

7 голосов
/ 11 июля 2011

Сеансовая фабрика пытается автоматизировать все классы в сборке, содержащей ваш класс Agency, на основе этой директивы: Add(AutoMap.AssemblyOf<Agency>(cfg)). Поскольку в сборке AgencyMap, а ClassMap<> не имеет свойства Id, FNH выдает ошибку.

Если вы хотите использовать ClassMap<> конфигурации, вместо (или в дополнение к) объявления конфигурации автоматического сопоставления, объявите свободное отображение:

m.FluentMappings.AddFromAssemblyOf<Agency>();

Если вам не нужны автоматические сопоставления, удалите директиву .AutoMappings.Add.

Однако, если вы хотите использовать AutoMappings, вам нужно сообщить FNH, какие классы вы хотите отобразить. Чтобы справиться с этим, я обычно определяю интерфейс маркера:

public abstract class Entity : IPersistable
{
    public virtual int Id { get; set; }
}

public interface IPersistable
{
}

Затем в классе, который я наследую от DefaultAutomappingConfiguration, я говорю FNH отображать только те классы, которые имеют этот интерфейс (вы можете ограничить сопоставленные классы, как считаете нужным):

public class EntityAutoMappingConfiguration : DefaultAutomappingConfiguration
{
    public override bool ShouldMap(Type type)
    {
        return type.GetInterfaces().Contains(typeof (IPersistable));
    }

}

Для обработки сопоставления первичного ключа я создаю класс соглашения:

public class PrimaryKeyNamePlusId : IIdConvention 
{
    public void Apply(IIdentityInstance instance)
    {
        instance.Column(instance.EntityType.Name+"Id");
    }
}

Наконец, я настраиваю свой SessionFactory для использования классов конфигурации / соглашения:

 m.AutoMappings.AssemblyOf<Entity>(new EntityAutoMappingConfiguration())
            .IgnoreBase<Entity>()
            .UseOverridesFromAssemblyOf<Entity>()
            .Conventions.AddFromAssemblyOf<Entity>();
0 голосов
/ 11 июля 2011

Вы не можете использовать ClassMap в сочетании с автоматом, если вы не сконфигурируете автомат для игнорирования Entites, для которого вы используете ClassMap, и их соответствующие файлы сопоставления.

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

/// <summary>
/// Add this attribute to entity classes which should be automapped by Fluent.
/// </summary>
[AttributeUsage(AttributeTargets.Class)]
class AutomapAttribute : Attribute
{
}

И в моем DefaultAutomappingConfiguration классе переопределения:

    public override bool ShouldMap(Type type)
    {
        return (type.Namespace == "Data.Entities" 
            && type.GetCustomAttributes(typeof(AutomapAttribute), false).Length > 0);
    }

Конечно, вам не нужно проверять наличие атрибута, если вы просто сохраняете свои автоматически обработанные сущности в пространстве имен, отличном от других классов.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...