Код EF4.1 Первый сложный тип в качестве первичного ключа - PullRequest
11 голосов
/ 02 апреля 2011

В настоящее время я пытаюсь реализовать репозитории для своих доменных объектов с помощью RC Entity Framework 4.1 и его подхода «сначала код». Теперь у меня есть сущность домена "Voyage", которая имеет уникальный идентификатор, инкапсулированный в тип "VoyageNumber"

public class VoyageNumber
{
    private readonly string number;

    public VoyageNumber(string number)
    {
        Validate.NotNull(number, "VoyageNumber is required");

        this.number = number;
    }

    public string Id
    {
        get { return number; }
    }

Теперь я получаю исключение, когда я делаю это в конфигурации моего DbContext:

modelBuilder.Entity<Voyage>().HasKey<VoyageNumber>(k => k.VoyageNumber);

Недвижимость 'VoyageNumber' не может быть используется в качестве ключевого свойства объекта 'Domain.Model.Voyages.Voyage', потому что тип свойства не является допустимым ключом тип. Только скалярные типы, строки и byte [] - поддерживаемые типы ключей.

а также, когда я пытаюсь это сделать:

modelBuilder.Entity<Voyage>().HasKey<string>(k => k.VoyageNumber.Id);

Выражение свойств 'k => k.VoyageNumber.Id 'недействителен. выражение должно представлять свойство: C #: 't => t.MyProperty'

Неужели мне действительно нужно уничтожить мой VoyageNumber и заменить его на примитивный тип?

Ответы [ 3 ]

14 голосов
/ 02 апреля 2011

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

0 голосов
/ 13 июня 2017

Мы можем решить это с помощью ниже. Надеюсь, это полезно.

public class TestPaperResultId: ValueObject
{
    public TestPaperResultId(string testPaperId, string userId)
    {
        TestPaperId = testPaperId;
        UserId = userId;
    }

    protected TestPaperResultId() { }

    public string TestPaperId { get; protected set; }
    public string UserId { get; protected set; }

    public override string ToString()
    {
        return $"{TestPaperId}_{UserId}";
    }
}

public class TestPaperResult : AggregateRoot
{
    private TestPaperResultId _id;

    public TestPaperResultId Id
    {
        get => _id ?? (_id = new TestPaperResultId(TestPaperId, UserId));
        protected set
        {
            TestPaperId = value.TestPaperId;
            UserId = value.UserId;
            _id = value;
        }
    }

    public string TestPaperId { get; protected set; }

    public string UserId { get; protected set; }

    protected TestPaperResult() { }

    public TestPaperResult(TestPaperResultId id,
                           decimal fullmarks)
    {
        Id = id;
        Fullmarks = fullmarks;
    }
}

в dbContext:

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
    base.OnModelCreating(modelBuilder);

    modelBuilder.Entity<TestPaperResult>()
                .Ignore(t => t.Id)
                .HasKey(t => new {t.TestPaperId, t.UserId});
 }

в репозитории:

 public Task<TestPaperResult> FindTestPaperResultAsync(TestPaperResultId id)
 {
     return GetByKeyAsync<TestPaperResult>(id.TestPaperId, id.UserId);
 }
0 голосов
/ 08 апреля 2016

Для изолированного класса вы можете сделать обходной путь только для чтения, добавив метод «get» в ваш DbContext, который выполняет SqlQuery<> и отображает таблицу внутри класса (старомодным способом).

Я разработал минимальный тестовый пример: https://github.com/timabell/ef-complex-pk

Например,

public class TestDbContext : DbContext
{

    public IEnumerable<UberWidget> GetUberWidgets()
    {
        return Database.SqlQuery<WidgetSqlDto>("select WidgetId, Name from Widgets")
            .Select(dto => new UberWidget
            {
                UberWidgetId = new IdWrap { IdWrapId = dto.WidgetId },
                Name = dto.Name
            });
    }
}
...