Мне нужен один столбец в моей базе данных, рассчитываемый базой данных как (сумма строк) - (сумма строкb). Для создания базы данных я использую модель «сначала код».
Вот что я имею в виду:
public class Income {
[Key]
public int UserID { get; set; }
public double inSum { get; set; }
}
public class Outcome {
[Key]
public int UserID { get; set; }
public double outSum { get; set; }
}
public class FirstTable {
[Key]
public int UserID { get; set; }
public double Sum { get; set; }
// This needs to be calculated by DB as
// ( Select sum(inSum) FROM Income WHERE UserID = this.UserID)
// - (Select sum(outSum) FROM Outcome WHERE UserID = this.UserID)
}
Как я могу добиться этого в EF CodeFirst?
ValueGeneratedOnAddOrUpdate()
посколькуHasDatabaseGeneratedOption
он не существует. В противном случае отличный ответ.public string ChargePointText { get; set; } public class FirstTable { [Key] public int UserID { get; set; } [DatabaseGenerated(DatabaseGeneratedOption.Computed)] public string Summ { get { return /* do your sum here */ } private set { /* needed for EF */ } } }
Рекомендации:
источник
/* do your sum here */
не применяется. Если свойство вычисляется внутри класса, оно должно быть аннотировано как[NotMapped]
. Но значение поступает из базы данных, поэтому это должно быть простоget
свойство.По состоянию на 2019 год ядро EF позволяет чистым образом вычислять столбцы с помощью свободного API:
Предположим, что
DisplayName
это вычисляемый столбец, который вы хотите определить, вы должны определить свойство как обычно, возможно, с помощью метода доступа к частному свойству, чтобы предотвратить его назначение.public class Person { public int PersonId { get; set; } public string FirstName { get; set; } public string LastName { get; set; } // this will be computed public string DisplayName { get; private set; } }
Затем в построителе модели обратитесь к нему с помощью определения столбца:
protected override void OnModelCreating(ModelBuilder modelBuilder) { modelBuilder.Entity<Person>() .Property(p => p.DisplayName) // here is the computed query definition .HasComputedColumnSql("[LastName] + ', ' + [FirstName]"); }
Для получения дополнительной информации посетите MSDN .
источник
В EF6 вы можете просто настроить параметр сопоставления, чтобы игнорировать вычисленное свойство, например:
Определите вычисление для свойства get вашей модели:
public class Person { // ... public string FirstName { get; set; } public string LastName { get; set; } public string FullName => $"{FirstName} {LastName}"; }
Затем установите его, чтобы игнорировать конфигурацию модели.
protected override void OnModelCreating(ModelBuilder modelBuilder) { //... modelBuilder.Entity<Person>().Ignore(x => x.FullName) }
источник
Один из способов - сделать это с помощью LINQ:
var userID = 1; // your ID var income = dataContext.Income.First(i => i.UserID == userID); var outcome = dataContext.Outcome.First(o => o.UserID == userID); var summ = income.inSumm - outcome.outSumm;
Вы можете сделать это в своем объекте POCO
public class FirstTable
, но я бы не стал предлагать, потому что считаю, что это плохой дизайн.Другой способ - использовать представление SQL. Вы можете читать представление как таблицу с Entity Framework. А в коде представления вы можете производить вычисления или что угодно. Просто создайте представление вроде
-- not tested SELECT FirstTable.UserID, Income.inCome - Outcome.outCome FROM FirstTable INNER JOIN Income ON FirstTable.UserID = Income.UserID INNER JOIN Outcome ON FirstTable.UserID = Outcome.UserID
источник
Я бы сделал это, просто используя модель представления. Например, вместо того, чтобы иметь класс FirstTable в качестве объекта db, не лучше ли иметь класс модели представления с именем FirstTable, а затем иметь функцию, которая используется для возврата этого класса, который будет включать вычисленную сумму? Например, ваш класс будет просто:
public class FirstTable { public int UserID { get; set; } public double Sum { get; set; } }
И тогда у вас будет функция, которую вы вызываете, которая возвращает вычисленную сумму:
public FirsTable GetNetSumByUserID(int UserId) { double income = dbcontext.Income.Where(g => g.UserID == UserId).Select(f => f.inSum); double expenses = dbcontext.Outcome.Where(g => g.UserID == UserId).Select(f => f.outSum); double sum = (income - expense); FirstTable _FirsTable = new FirstTable{ UserID = UserId, Sum = sum}; return _FirstTable; }
В основном то же самое, что и представление SQL, и, как упоминал @Linus, я не думаю, что было бы хорошей идеей хранить вычисленное значение в базе данных. Просто мысли.
источник
I don't think it would be a good idea keeping the computed value in the database
- особенно если вы собираетесь использовать Azure SQL, который начнет зайти в тупик при большой нагрузке.Я наткнулся на этот вопрос, когда пытался получить модель EF Code First со строковым столбцом «Slug», производным от другого строкового столбца «Name». Подход, который я использовал, был немного другим, но сработал хорошо, поэтому я поделюсь им здесь.
private string _name; public string Name { get { return _name; } set { _slug = value.ToUrlSlug(); // the magic happens here _name = value; // but don't forget to set your name too! } } public string Slug { get; private set; }
Что хорошо в этом подходе, так это то, что вы получаете автоматическую генерацию слагов, но никогда не открываете установщик слагов. Метод .ToUrlSlug () не является важной частью этого поста, вы можете использовать что угодно вместо него, чтобы выполнять нужную работу. Ура!
источник
Slug
наName
? Как написано в настоящее время,Name
установщик даже не должен компилироваться.