EF Code First: раздельное создание объектов в БД с наследованием TFT - PullRequest
2 голосов
/ 14 февраля 2012

Пример использования

Пользователь зарегистрировался на сайте (добавление записи в таблицу Users).Затем переходит на электронную почту и подтверждает регистрацию.Ссылка для подтверждения перенаправляет на страницу с формой редактирования человека, пользователь заполняет форму и отправляет ее (добавляя запись в таблицу Персоны).

Техническое описание

У меня естьПростое 2-х объектное наследование Table-Per-Type, определенное в модели EF.

Объекты

public class User
{
    public Guid Id { get; set; }
    public string Name { get; set; }
    public string Email { get; set; }
    public string Password { get; set; }
}

public class Person : User
{
    public string FirstName { get; set; }
    public string MiddleName { get; set; }
    public string LastName { get; set; }
}

База данных

public class MainDataContext : DbContext
{
    public DbSet<User> Users { get; set; }
    public DbSet<Person> Persons { get; set; }

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        base.OnModelCreating(modelBuilder);
        var configs = modelBuilder.Configurations;
        configs.Add(new UserConfiguration());
        configs.Add(new PersonConfiguration());
    }
}

Конфигурации

internal class UserConfiguration : EntityTypeConfiguration<User>
{
    internal UserConfiguration()
    {
        ToTable("Users");

        HasKey(x => x.Id);

        Property(x => x.Id)
            .HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
        Property(x => x.Name)
            .IsRequired()
            .HasMaxLength(128);
        Property(x => x.Password)
            .IsRequired()
            .HasMaxLength(128);
        Property(x => x.Email)
            .IsRequired()
            .HasMaxLength(128);
    }
}
internal class PersonConfiguration : EntityTypeConfiguration<Person>
{
    internal PersonConfiguration()
    {
        ToTable("Persons");

        Property(x => x.FirstName)
            .IsRequired()
            .HasMaxLength(16);
        Property(x => x.MiddleName)
            .IsOptional()
            .HasMaxLength(16);
        Property(x => x.LastName)
            .IsRequired()
            .HasMaxLength(16);
    }
}

Необходимо последовательно создавать связанные объекты (FK) в DbSets, что-то вроде этого:

    var db = new MainDataContext();
    var user = new User
    {
        Name = "someUser",
        Password = "somePassword",
        Email = "someEmail"
    };
    db.Users.Add(user);
    db.SaveChanges();
    // After some time in other some place
    var person = new Person
    {
        Id = user.Id,
        FirstName = "someFirstName",
        LastName = "someLastName"
    };
    db.Persons.Add(person);
    db.SaveChanges();

После последнегоSaveChanges DbEntityValidationError было обнаружено: «Проверка не удалась для одной или нескольких сущностей. Для получения дополнительной информации см. Свойство EntityValidationErrors».Есть 3 ошибки проверки для обязательных полей пользователя.

Как отдельно добавить записи в DbSets, связанные с FK (наследование)?

UPDATE

Я нашел одно решение.Но для этого вы должны удалить старого пользователя.Я хотел бы сделать это без удаления, потому что, если таблица Users будет связана с другими таблицами, то это сделает невозможным удаление.

    var db = new MainDataContext();
    var user = new User
    {
        Name = "someUser",
        Password = "somePassword",
        Email = "someEmail"
    };
    db.Users.Add(user);
    db.SaveChanges();
    // After some time in other some place
    var person = new Person
    {
        Id = user.Id,
        Name = user.Name,
        Password = user.Password,
        Email = user.Email,
        FirstName = "someFirstName",
        LastName = "someLastName"
    };
    db.Users.Remove(user);
    db.Persons.Add(person);
    db.SaveChanges();

Но возникла другая проблема - генерируется новый Guid для объекта person.

Как решить проблему, не удаляя старую запись пользователя?

Ответы [ 2 ]

1 голос
/ 04 декабря 2012

После включения варианта использования Обновление:

Здесь не следует использовать наследование.Вы должны использовать композицию и взаимно-однозначные отношения между сущностями:

public class User
{
    public Guid Id { get; set; }
    public string Name { get; set; }
    public string Email { get; set; }
    public string Password { get; set; }
    public virtual UserInfo Information{get;set;}
}

internal class UserConfiguration : EntityTypeConfiguration<User>
{
    internal UserConfiguration()
    {
        ToTable("Users");

        HasKey(x => x.Id);

        Property(x => x.Id)
            .HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
        Property(x => x.Name)
            .IsRequired()
            .HasMaxLength(128);
        Property(x => x.Password)
            .IsRequired()
            .HasMaxLength(128);
        Property(x => x.Email)
            .IsRequired()
            .HasMaxLength(128);        
    }
}

public class UserInfo
{
    [ForeignKey("InfosUser")]
    [Key]
    public UserId {get;set;}
    public string FirstName { get; set; }
    public string MiddleName { get; set; }
    public string LastName { get; set; }
    public virtual User InfosUser {get;set;}
}

internal class UserInfoConfiguration : EntityTypeConfiguration<UserInfo>
{
    internal UserInfoConfiguration()
    {
        ToTable("Persons");

        Property(x => x.FirstName)
            .IsRequired()
            .HasMaxLength(16);
        Property(x => x.MiddleName)
            .IsOptional()
            .HasMaxLength(16);
        Property(x => x.LastName)
            .IsRequired()
            .HasMaxLength(16);
        HasRequired(ui=>ui.InfosUser).WithOptional(u=>u.Information)
    }
}

и использовать ее:

    var db = new MainDataContext();
    var user = new User
    {
        Name = "someUser",
        Password = "somePassword",
        Email = "someEmail"
    };
    db.Users.Add(user);
    db.SaveChanges();
    // After some time in other some place
    var user = db.GetPersonFromDb(Id);// Get early saved person from db
    var information = new UserInfo
    {
         FirstName = "someFirstName",
         LastName = "someLastName",
    }
    user.Information = information;
    db.SaveChanges();
0 голосов
/ 07 декабря 2012

Кажется, проблема в том, что созданный объект не является объектом Person.Если вы вставите значение User.id в таблицу Person, вы сможете найти пользователя как Person и обновить его.

        Guid id;
        using (var db = new MainDataContext())
        {
            var user = new User
            {
                Name = "someUser",
                Password = "somePassword",
                Email = "someEmail"
            };
            db.Users.Add(user);
            db.SaveChanges();
            id = user.Id;
        }

        // After some time in other some place
        //pause here and insert the id GUID into the Person table

        using (var db = new MainDataContext())
        {
            var person = db.Persons.Find(id);
            person.FirstName = "someFirstName";
            person.LastName = "someLastName";
            db.SaveChanges();
        }

Добавление идентификатора пользователя в таблицу Person за пределами EF приведет к повышению скорости передачи.ты желаешь.Вы можете «продвигать» объект от пользователя к человеку с помощью прямого обновления базы данных.

...