#c# #entity-framework-core
#c# #entity-framework-core
Вопрос:
У меня есть Account
объект, для которого я хочу вызвать Subscription
свойство CurrentSubscription
.
public class Account
{
public int Id { get; set; }
public Subscription CurrentSubscription { get; set; }
}
public class Subscription
{
public int Id { get; set; }
public int AccountId { get; set; }
public Account Account { get; set; }
public DateTime Start { get; set; }
public DateTime? End { get; set; }
}
На самом деле для данной учетной записи может быть несколько Subscription
строк, но бизнес-правило диктует, что когда-либо будет только одна (или ни одной) с EndDate
of null
( Account
текущая подписка). В моей модели меня не волнуют другие, когда я получаю учетную запись, поскольку я только после текущей.
Как я могу сказать EF, чтобы сделать это? Игра с fluent API не предполагает, что в него что-то встроено PropertyBuilder
, и каждый HasDefaultValueSql
найденный мной пример имеет тривиальное Sql
значение, "GETDATE()"
в отличие от чего-то параметризованного, что для этого нужно было бы ( ..where AccountId = ?
) .
Итак, я застрял .. есть идеи?
Комментарии:
1. » Как я могу сказать EF сделать это? » Вы не можете. То, что вы описываете, — это представление
Account
объекта, имеющего коллекциюSubscription
s. Следовательно, не может быть отображен на уровне объекта и должен быть смоделирован как view (DTO / ViewModel и т. Д.) В общем случае модель сущности EF представляет модель хранилища, а не модель бизнес-правил.
Ответ №1:
Это должно сработать в вашем случае:
public class Account
{
public int Id { get; set; }
//Collection automatically loaded by EF
public virtual List<Subscription> Subscriptions { get; set; }
// Returns Only (or none) subscription with null End date
public Subscription CurrentSubscription => Subscriptions.SingleOrDefault(r=>r.End == null);
}
Account.Subscriptions
-коллекция автоматически (лениво) загружается Entity Framework, если внешний ключ правильно установлен в классе подписки (или с помощью Fluent API):
public class Subscription
{
public int Id { get; set; }
public int AccountId { get; set; }
[ForeignKey("AccountId")]
public Account Account { get; set; }
public DateTime Start { get; set; }
public DateTime? End { get; set; }
}
Ответ №2:
На самом деле для данной учетной записи может быть несколько строк подписки, но бизнес-правило диктует, что когда-либо будет только одна (или ни одной) с конечной датой null (текущая подписка учетной записи). В моей модели меня не волнуют другие, когда я получаю учетную запись, поскольку я только после текущей. Как я могу сказать EF, чтобы сделать это?
Ядро Entity Framework имеет точное решение, которое вы ищете, и это отношения EF Core: взаимно однозначный.
Итак, ваша Subscription
конфигурация объекта должна быть следующей:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Entity<Subscription>().HasOne(s => s.Account)
.WithOne(a => a.CurrentSubscription).HasForeignKey<Subscription>(s => s.AccountId);
}
Более того, поскольку для so будет один или ноль Subscription
Account
, мы можем удалить Id
столбец из Subscription
объекта и сделать AccountId
его первичным ключом Subscription
объекта следующим образом:
public class Subscription
{
public int AccountId { get; set; }
public Account Account { get; set; }
public DateTime Start { get; set; }
public DateTime? End { get; set; }
}
Тогда ваша Subscription
конфигурация объекта должна быть следующей:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Entity<Subscription>(s =>
{
s.HasKey(sc => sc.AccountId); // <-- AccountId as primary key
s.HasOne(sc => sc.Account).WithOne(a => a.CurrentSubscription)
.HasForeignKey<Subscription>(sc => sc.AccountId);
});
}