Я ходил по кругу с этим и, похоже, не в состоянии гуглить правильные ответы - даже после нескольких часов, потраченных на это, так что вы - мое последнее средство!
Настройка
В моем веб-приложении я хотел бы разрешить пользователям использовать различные механизмы аутентификации для доступа к своим учетным записям. В дополнение к обычному пользователю / паролю, я хотел бы позволить им использовать OpenId от Google, OpenId от Yahoo или даже Facebook. Это кажется довольно простым для отображения на классы: абстрактный Account
с несколькими <something>Account
классами, наследующими некоторые базовые свойства от Account
. Я начал со следующих двух классов:
public abstract class Account
{
public int Id { get; set; }
public int OwnerId { get; set; }
public virtual Person Owner { get; set; }
}
public class OpenIdAccount : Account
{
public string Identifier { get; set; }
}
Будучи немного перфекционистом и много занимаясь db dev в своей повседневной работе, я решил, что таблица для каждого типа (TPT) будет наиболее желательным вариантом. Поскольку EF4 по умолчанию использует TPH, на стороне DbContext я определил следующее:
public class MySampleDb : DbContext
{
public DbSet<Person> People { get; set; }
public DbSet<Account> Accounts { get; set; }
public DbSet<OpenIdAccount> OpenIdAccounts { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Account>().MapHierarchy(a => new
{
a.Id,
a.OwnerId
}).ToTable("Account");
modelBuilder.Entity<OpenIdAccount>().MapHierarchy(oid => new
{
oid.Id,
oid.Identifier
}).ToTable("OpenIdAccount");
}
}
Теперь я хотел начать с нескольких простых тестов и подумал, что заполнение базы данных при каждом запуске - это хороший способ иметь согласованные данные для работы:
protected override void Seed(MySampleDb context)
{
Person johns = new Person
{
Id = 1,
Nickname = "John Skeet"
};
OpenIdAccount google = new OpenIdAccount
{
Id = 2,
OwnerId = 1,
Identifier = "https://www.google.com/accounts/o8/id?id=AItOawnmUz4e6QIn9mgd98WMAbnzC25sji5lpSM"
};
context.People.Add(johns);
context.Accounts.Add(google);
context.SaveChanges();
}
(Не уверен, почему, но DbContext, похоже, никогда не пытался заполнить мою базу данных вышеуказанными данными, пока я явно не назвал .SaveChanges()
... какие-нибудь идеи?)
Проблемы
One
В базе данных EF не определял никаких отношений между Account
и OpenIdAccount
. Это был первый предупредительный знак, что-то было не так; несомненно, OpenIdAccount должен иметь Id
, определенный как PK и FK, указывающий на Account.Id?
Два
Я получаю следующее UpdateException
, когда .net пытается выполнить .SaveChanges()
:
Значение, разделяемое между сущностями или ассоциациями
генерируется в нескольких местах. Проверь это
отображение не разделяет EntityKey на несколько
Сгенерированные магазином столбцы.
Следующие шаги
Сегодня мой первый день с EF4 и первой разработкой кода. Потратив много часов, читая о EF4 + code-first + custom mapping, я пришел к точке, где я навсегда застрял и мне нужен удар в правильном направлении, прежде чем я смогу начать снова :-)
Так что я надеюсь, что вы, ребята, сможете понять вышесказанное и объяснить какую-то глупую ошибку / недоразумение с моей стороны!