EF कोड प्रथम में परिकलित स्तंभ


80

मुझे अपने डेटाबेस में एक पंक्तियों की गणना डेटाबेस (पंक्तियों के योग) के रूप में करनी है - (पंक्तियों की राशि)। मैं अपना डेटाबेस बनाने के लिए कोड-प्रथम मॉडल का उपयोग कर रहा हूं।

यही है जो मेरा मतलब है:

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 में मैं इसे कैसे प्राप्त कर सकता हूं?

जवाबों:


137

आप अपने डेटाबेस तालिकाओं में कंप्यूटेड कॉलम बना सकते हैं । EF मॉडल में आप DatabaseGeneratedविशेषता के साथ संबंधित गुणों को एनोटेट करते हैं :

[DatabaseGenerated(DatabaseGeneratedOption.Computed)]
public double Summ { get; private set; } 

या धाराप्रवाह मानचित्रण के साथ:

modelBuilder.Entity<Income>().Property(t => t.Summ)
    .HasDatabaseGeneratedOption(DatabaseGeneratedOption.Computed)

जैसा कि मतिजा ग्रैसिक ने सुझाव दिया था और एक टिप्पणी में कहा, यह संपत्ति बनाने के लिए एक अच्छा विचार है private set, क्योंकि आप इसे कभी भी आवेदन कोड में सेट नहीं करना चाहेंगे। एंटिटी फ्रेमवर्क में निजी बाशिंदों को कोई समस्या नहीं है।

नोट: EF .NET कोर के लिए आपको ValueGeneratedOnAddOrUpdate का उपयोग करना चाहिए क्योंकि HasDatabaseGeneratedOption नहीं है, जैसे:

modelBuilder.Entity<Income>().Property(t => t.Summ)
    .ValueGeneratedOnAddOrUpdate()

26
मैं इसके बारे में जानता हूं लेकिन मैं अपने डेटाबेस से EF के माध्यम से गणना करने के लिए एक सूत्र कैसे जोड़ सकता हूं, ताकि यह कंसोल कमड अपडेट-डेटाबेस द्वारा बनाया जाए?
कोडमैन ने

10
कृपया इसे अपने प्रश्न में स्पष्ट रूप से बताएं। इसका मतलब है कि आप माइग्रेशन चाहते हैं कि एक संगणित कॉलम बनाएं। यहाँ एक उदाहरण है
गर्ट अर्नोल्ड

2
क्या सेटर को निजी होना चाहिए?
१०:१५

1
@ शेरवेन हाँ, शायद ऐसा करने के लिए बेहतर है।
गर्ट अर्नोल्ड

6
इस उत्तर को जोड़ने के लिए अद्यतन किया जाना चाहिए कि ईएफ कोर के लिए, मॉडल बिल्डर को विधि का उपयोग करना चाहिए ValueGeneratedOnAddOrUpdate()क्योंकि HasDatabaseGeneratedOptionमौजूद नहीं है। अन्यथा, महान जवाब।
मैक्स

34
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 */ }
    }
}

संदर्भ:


निजी सेट जोड़ने के लिए +1। नई वस्तुओं को जोड़ते समय कंप्यूटेड कॉलम सेट नहीं होना चाहिए।
ताहिर

1
इस प्रश्न को फिर से देखना अच्छा लगा और अब मैं देख रहा हूं कि यह भाग /* do your sum here */लागू नहीं होता है। यदि संपत्ति की गणना वर्ग के अंदर की जाती है, तो इसे एनोटेट किया जाना चाहिए [NotMapped]। लेकिन मूल्य डेटाबेस से आता है, इसलिए यह केवल एक साधारण getसंपत्ति होना चाहिए ।
गर्ट अर्नोल्ड

1
@GertArnold यहां देखें - "चूंकि
FullName

@AlexFoxGill फिर क्या बात है? यदि आपके गतिशील रूप से उन्हें "सिंक से बाहर निकलने" की स्थिति में हर बार पुनर्गणना करने जा रहे हैं, तो संगणित मूल्यों को संग्रहीत करने से क्यों परेशान करें?
रुडी

@RuudLenders ताकि आप LINQ प्रश्नों में गणना किए गए कॉलम का उपयोग कर सकें।
एलेक्सफॉक्सगिल

15

2019 तक, ईएफ कोर आपको धाराप्रवाह एपीआई के साथ एक साफ तरीके से गणना किए गए कॉलम की अनुमति देता है:

मान लीजिए कि 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 पर एक नज़र डालें ।


3

EF6 में, आप किसी गणना की गई संपत्ति को अनदेखा करने के लिए मैपिंग सेटिंग को इस तरह कॉन्फ़िगर कर सकते हैं:

अपने मॉडल की संपत्ति पर गणना को परिभाषित करें:

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)
}

1

एक तरह से यह 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

0

मैं सिर्फ एक दृश्य मॉडल का उपयोग करके इसके बारे में जाना होगा। उदाहरण के लिए, एक डीबी इकाई के रूप में फर्स्टटैबल क्लास के बजाय क्या आप बेहतर नहीं होंगे कि फ़र्स्टटेबल नामक एक व्यू मॉडल क्लास हो और फिर एक फ़ंक्शन है जिसका उपयोग इस क्लास को वापस करने के लिए किया जाता है जिसमें गणना की गई राशि शामिल होगी? उदाहरण के लिए आपकी कक्षा बस होगी:

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 के रूप में एक ही उल्लेख किया है मुझे नहीं लगता कि यह डेटाबेस में गणना मूल्य रखते हुए एक अच्छा विचार होगा। बस कुछ विचार।


+1 के लिए I don't think it would be a good idea keeping the computed value in the database- विशेषकर यदि आप एज़्योर एसक्यूएल का उपयोग करने जा रहे हैं जो भारी लोड पर गतिरोध शुरू कर देगा।
पायोटर कुला

1
@ppumkin ज्यादातर मामलों में, डीबी में बेहतर प्रदर्शन होने वाला है। कुछ ऐसा सोचें जैसे 'सबसे हालिया टिप्पणी आईडी'। आप उनमें से केवल एक को लेने के लिए हर कमेंट को वापस खींचना नहीं चाहते हैं। न केवल आप डेटा और मेमोरी को बर्बाद कर रहे हैं, बल्कि आप स्वयं डीबी पर लोड भी बढ़ा रहे हैं, और आपने वास्तव में अधिक पंक्तियों पर साझा ताले डाल दिए हैं। क्या अधिक है, आपको हर समय बहुत सारी पंक्तियों को अपडेट करना होगा , जो संभवतः एक डिज़ाइन है जिसे समीक्षा की आवश्यकता है।
जोब्रेकॉस

ठीक। मेरा तात्पर्य उन्हें स्मृति, संगणित मूल्यों, कैश्ड में रखना है। हर आगंतुक के लिए डेटाबेस पर मत जाओ। इसके मुद्दों का कारण बनने जा रहा है। मैंने ऐसा कई बार देखा है।
पायोटर कुला

-2

जब एक स्ट्रिंग कॉलम "स्लग" के साथ EF कोड पहला मॉडल रखने की कोशिश कर रहा था, तो मैं इस सवाल से टकरा गया, दूसरे स्ट्रिंग कॉलम "नाम" से लिया गया। मेरे द्वारा लिया गया दृष्टिकोण थोड़ा अलग था लेकिन अच्छी तरह से काम किया इसलिए मैं इसे यहाँ साझा करूँगा।

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सेटर को संकलन भी नहीं करना चाहिए।
शुभ अंक

नहीं, आपके संपादन से पहले, यह एक व्यावहारिक उदाहरण था। आपके संपादन के बाद, इसका कोई मतलब नहीं है।
शुभ अंक
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.