2017-03-08 6 views
5

मैं एक बहु किरायेदार आवेदन लिख रहा हूं। लगभग सभी तालिकाओं में यह निर्दिष्ट करने के लिए "खाता आईडी" है कि कौन से किरायेदार के पास रिकॉर्ड है। मेरे पास एक सारणी है जिसमें "विक्रेताओं" की एक सूची है जो सभी किरायेदारों के पास पहुंच है, इसमें खाता आईडी नहीं है।इकाई फ्रेमवर्क मल्टी टेनेंट अनुकूलित तालिका

कुछ किरायेदार एक विक्रेता रिकॉर्ड पर कस्टम फ़ील्ड जोड़ना चाहते हैं।

मैं इसे कोड प्रथम इकाई फ्रेमवर्क में कैसे सेट अप करूं? यह अब तक मेरा समाधान है लेकिन मुझे सभी पसंदीदा विक्रेताओं को लाने की ज़रूरत है क्योंकि मैं ईएफ में उप-क्वेरी नहीं लिख सकता हूं और फिर जब मैं रिकॉर्ड अपडेट करता हूं, तो हटाए जा रहे हैं।

public class Vendor 
{ 
    public int Id { get;set;} 
    public string Name { get; set; } 
} 

public class TenantVendor 
{ 
    public int AccountId { get;set;} 
    public int VendorId{ get;set;} 
    public string NickName { get; set; } 
} 


// query 
// how do I only get single vendor for tenant? 
var vendor = await DbContext.Vendors 
          .Include(x => x.TenantVendors) 
          .SingleAsync(x => x.Id == vendorId); 

// now filter tenant's favorite vendor 
// problem: if I update this record later, it deletes all records != account.Id 
vendor.TenantVendors= vendor.FavoriteVendors 
          .Where(x => x.AccountId == _account.Id) 
          .ToList(); 

मुझे पता है कि मुझे एक बहु-कॉलम विदेशी कुंजी का उपयोग करने की आवश्यकता है, लेकिन मुझे इसे स्थापित करने में समस्या हो रही है।

स्कीमा .. ऐसा दिखाई देगा

Vendor 
Id 

FavVendor 
VendorId 
AccountId 
CustomField1 

तब मैं विक्रेता क्वेरी कर सकता है, खाते में लॉग इन के लिए FavVendor हो और मेरी प्रमुदित रास्ते पर चलते हैं।

मेरे वर्तमान समाधान है, जो मुझे एक अतिरिक्त "VENDOR_ID" विदेशी कुंजी देता है, लेकिन यह निर्धारित नहीं करता है ठीक से

यह संभव हो जाना चाहिए "एक करने के लिए एक" संबंध स्थापित करने और विदेशी महत्वपूर्ण हो होने से "विक्रेता आईडी" और "खाता क्रमांक"

अब इकाई ढांचे में इस स्थापना का प्रयास कर रहे ...

public class Vendor 
{ 
    public int Id { get; set; } 
    public string Name { get; set; } 

    public virtual FavVendor FavVendor { get; set; } 
} 

public class FavVendor 
{ 
    public string NickName { get; set; } 

    [Key, Column(Order = 0)] 
    public int VendorId { get; set; } 
    public Vendor Vendor { get; set; } 

    [Key, Column(Order = 1)] 
    public int AccountId { get; set; } 
    public Account Account { get; set; } 
} 


// query to get data 
    var dbVendorQuery = dbContext.Vendors 
     .Include(x => x.FavVendor) 
     .Where(x => x.FavVendor == null || x.FavVendor.AccountId == _account.Id) ; 

// insert record 
if (dbVendor.FavVendor == null) 
{ 
    dbVendor.FavVendor = new FavVendor() 
    { 
     Account = _account, 
    }; 
    } 
    dbVendor.FavVendor.NickName = nickName; 

    dbContext.SaveChanges(); 

enter image description here

इसके अलावा निम्न त्रुटि प्राप्त जब मैं कोशिश करते हैं और FavVendor.Vendor

पर विदेशी कुंजी सेट

FavVendor_Vendor_Source: बहुलता रिश्ते में भूमिका 'FavVendor_Vendor_Source' 'FavVendor_Vendor' में मान्य नहीं है। क्योंकि निर्भर भूमिका गुण प्रमुख गुण नहीं हैं, निर्भर भूमिका की बहुतायत की ऊपरी सीमा '*' होना चाहिए।

उत्तर

3

ट्रिकी मुद्दा चुनें। उन मामलों में से एक जहां डीटीओ और प्रक्षेपण आपको आवश्यक नियंत्रण प्रदान करता है। अभी भी शुद्ध ईएफ समाधान मौजूद है, लेकिन बहुत सावधानी से प्रोग्राम किया जाना चाहिए। मैं जितना कर सकता हूं उतने पहलुओं को कवर करने की कोशिश करूंगा।

के साथ शुरू करने दें।

यह एक "एक करने के लिए एक" संबंध स्थापित करने और विदेशी महत्वपूर्ण हो "विक्रेता आईडी" और "खाता क्रमांक"

यह संभव नहीं है होने से संभव हो जाना चाहिए। शारीरिक (स्टोर) संबंध one-to-many है (Vendor (एक) FavVendor को (कई)), हालांकि तार्किक एक विशिष्ट AccountId के लिए संबंध one-to-one है। लेकिन ईएफ केवल भौतिक संबंधों का समर्थन करता है, इसलिए तार्किक संबंधों का प्रतिनिधित्व करने का कोई तरीका नहीं है, जो अतिरिक्त गतिशील है।

संक्षेप में, संबंध आपके शुरुआती डिज़ाइन के रूप में one-to-many होना चाहिए।

public class Vendor 
{ 
    public int Id { get; set; } 
    public string Name { get; set; } 

    public ICollection<FavVendor> FavVendors { get; set; } 
} 

public class FavVendor 
{ 
    public string NickName { get; set; } 

    [Key, Column(Order = 0)] 
    public int VendorId { get; set; } 
    public Vendor Vendor { get; set; } 

    [Key, Column(Order = 1)] 
    public int AccountId { get; set; } 
} 

यह मेरा समाधान अब तक है हटाता है, लेकिन मैं सभी पसंदीदा विक्रेताओं लाने के लिए के बाद से मैं एफई में एक उप क्वेरी जब मैं रिकॉर्ड को अपडेट नहीं लिख सकते हैं और उसके बाद है,: यहाँ अंतिम मॉडल है हो रहा है

दोनों उपरोक्त मुद्दों को एक विशेष तरीके से कोड को wring करके हल किया जा सकता है।

पहले, निचले बाद से आलसी है और न ही उत्सुक लोड हो रहा है छानने का समर्थन करता है, एकमात्र शेष विकल्प explicit loading (लागू करने फिल्टर में वर्णित जब स्पष्ट रूप से संबंधित संस्थाओं लोड हो रहा है प्रलेखन के अनुभाग) या प्रक्षेपण है और संदर्भ नेविगेशन पर भरोसा करते हैं संपत्ति निर्धारण (जो वास्तव में स्पष्ट लोडिंग पर आधारित है)। साइड इफेक्ट्स से बचने के लिए, आलसी लोडिंग को शामिल इकाइयों के लिए बंद कर दिया जाना चाहिए (मैंने पहले से ही नेविगेशन गुणों से virtual कीवर्ड को हटाकर किया है) और अनजाने लोडिंग को खत्म करने के लिए डेटा पुनर्प्राप्ति हमेशा नए अल्पकालिक DbContext उदाहरणों के माध्यम से होनी चाहिए उसी नेविगेशन प्रॉपर्टी फ़िक्सअप सुविधा के कारण संबंधित डेटा का हम FavVendors के फ़िल्टरिंग पर भरोसा करते हैं।

FavVendors विशिष्ट खाते के लिए फ़िल्टर किया साथ प्राप्त कर रहा है विक्रेताओं:

public static partial class VendorUtils 
{ 
    public static Vendor GetVendor(this DbContext db, int vendorId, int accountId) 
    { 
     var vendor = db.Set<Vendor>().Single(x => x.Id == vendorId); 
     db.Entry(vendor).Collection(e => e.FavVendors).Query() 
      .Where(e => e.AccountId == accountId) 
      .Load(); 
     return vendor; 
    } 

    public static async Task<Vendor> GetVendorAsync(this DbContext db, int vendorId, int accountId) 
    { 
     var vendor = await db.Set<Vendor>().SingleAsync(x => x.Id == vendorId); 
     await db.Entry(vendor).Collection(e => e.FavVendors).Query() 
      .Where(e => e.AccountId == accountId) 
      .LoadAsync(); 
     return vendor; 
    } 
} 

या:

आईडी द्वारा एकल विक्रेता पुन: प्राप्त करने के लिए

ही कहा जा रहा साथ

, यहाँ के संचालन में से कुछ हैं अधिक सामान्य रूप से, विक्रेता पूछताछ के लिए (फ़िल्टरिंग, ऑर्डरिंग, पेजिंग इत्यादि के साथ पहले से ही लागू):

public static partial class VendorUtils 
{ 
    public static IEnumerable<Vendor> WithFavVendor(this IQueryable<Vendor> vendorQuery, int accountId) 
    { 
     var vendors = vendorQuery.ToList(); 
     vendorQuery.SelectMany(v => v.FavVendors) 
      .Where(fv => fv.AccountId == accountId) 
      .Load(); 
     return vendors; 
    } 

    public static async Task<IEnumerable<Vendor>> WithFavVendorAsync(this IQueryable<Vendor> vendorQuery, int accountId) 
    { 
     var vendors = await vendorQuery.ToListAsync(); 
     await vendorQuery.SelectMany(v => v.FavVendors) 
      .Where(fv => fv.AccountId == accountId) 
      .LoadAsync(); 
     return vendors; 
    } 
} 

कट इकाई से एक विशिष्ट खाते के लिए एक विक्रेता और FavVendor अपडेट कर रहा है:

public static partial class VendorUtils 
{ 
    public static void UpdateVendor(this DbContext db, Vendor vendor, int accountId) 
    { 
     var dbVendor = db.GetVendor(vendor.Id, accountId); 
     db.Entry(dbVendor).CurrentValues.SetValues(vendor); 

     var favVendor = vendor.FavVendors.FirstOrDefault(e => e.AccountId == accountId); 
     var dbFavVendor = dbVendor.FavVendors.FirstOrDefault(e => e.AccountId == accountId); 
     if (favVendor != null) 
     { 
      if (dbFavVendor != null) 
       db.Entry(dbFavVendor).CurrentValues.SetValues(favVendor); 
      else 
       dbVendor.FavVendors.Add(favVendor); 
     } 
     else if (dbFavVendor != null) 
      dbVendor.FavVendors.Remove(dbFavVendor); 

     db.SaveChanges(); 
    } 
} 

(async संस्करण के लिए सिर्फ Async तरीकों इसी पर await का उपयोग करें)

आदेश असंबंधित FavVendors को हटाने रोकने के लिए, आप पहले फ़िल्टर किए गएFavVendors डेटाबेस से लोड करते हैं, फिर पास ऑब्जेक्टके आधार परसामग्री या तो मौजूदा FavVendor रिकॉर्ड को नया, अपडेट या हटाएं।

संक्षेप में

, यह संभव है, लेकिन मुश्किल को लागू करने और बनाए रखने के लिए है (आप Vendor शामिल करने के लिए की जरूरत है और एक प्रश्न में FavVendors फ़िल्टर किए गए कुछ अन्य Vendor संदर्भित इकाई लौटने, क्योंकि आप ठेठ Include तरीकों का उपयोग नहीं कर सकते हैं, खासकर अगर)। आप Entity Framework Plus जैसे कुछ तृतीय पक्ष पैकेजों को आजमाने पर विचार कर सकते हैं, जिसमें क्वेरी फ़िल्टर और क्वेरी फ़िल्टर सुविधाएं क्वेरीिंग भाग को काफी सरल बना सकती हैं।

0

आपका ध्यान गलत

बजाय

Vendor  TenantVendor  One to many 
Vendor  FavVendor  One to many 
Account FavVendor  One to many 

है मुझे लगता है कि यह अपनी टिप्पणी में

Vendor  TenantVendor  OK 
TenantVendor FavVendor  One to many 

होना चाहिए

लॉग इन खाते के लिए FavVendor प्राप्त करें और मेरे मजेदार तरीके पर जाएं।

तो प्रत्येक खाते के लिए तुम्हारा निजी विक्रेताओं संबंध favVendor और TenantVendor

के बीच हैं

आपके प्रश्नों तो जैसे

// query 
// how do I only get single vendor for tenant? 
var vendor = DbContext.TenantVendor 
        .Include(x => x.Vendor) 
        .Where(x => x.VendorId == [your vendor id]) 
        .SingleOrDefault(); 

// now filter tenant's favorite vendor 
// problem: if I update this record later, it deletes all records != account.Id 
vendor.TenantVendors= DbContext.FavVendor 
        .Where(x => x.TenantVendor.AccountId = [account id]) 
        .ToList(); 

यहाँ नमूना EntityFramework नक्शा कुछ हो सकता है चाहिए

public class Vendor 
{ 
    public int Id { get; set; } 
    public string Name { get; set; } 
} 

public class TenantVendor 
{ 
    public int Id {get; set; 
    public int AccountId { get;set;} 
    public int VendorId{ get;set;} 
    public virtual Vendor Vendor {get;set;} 
    public string NickName { get; set; } 
} 

public class FavVendor 
{ 
    public int Id { get;set; } 

    public string NickName { get; set; } 
    public int TenantVendorId { get; set; } 
    public virtual TenantVendor TenantVendor { get; set; } 
} 

डीबीकॉन्टेक्स्ट

.... 

     protected override void OnModelCreating(DbModelBuilder builder) 
     { 


      builder.Entity<Vendor>() 
       .HasKey(t => t.Id) 
       .Property(p => p.Id).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity); 

      builder.Entity<TenantVendor>() 
       .HasKey(t => t.Id) 
       .Property(p => p.Id).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity); 

      builder.Entity<TenantVendor>() 
       .HasRequired(me => me.Vendor) 
       .WithMany() 
       .HasForeignKey(me => me.VendorId) 
       .WillCascadeOnDelete(false); 

      builder.Entity<FavVendor>() 
       .HasKey(t => t.Id) 
       .Property(p => p.Id).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity); 

      builder.Entity<FavVendor>() 
       .HasRequired(me => me.TenantVendor) 
       .WithMany() 
       .HasForeignKey(me => me.TenantVendorId) 
       .WillCascadeOnDelete(false); 

      } 

      .. 

मैं पहचान कुंजी मुझे लगता है कि बेहतर है, लेकिन है करने के लिए अपने समग्र कुंजी परिवर्तित अपने स्वाभाविक रूप से एफई द्वारा समर्थित नहीं

0

सबसे पहले, सवाल पूछने के तरीके को उत्तर देना मुश्किल है। यहां 2 प्रश्न हैं, एक कस्टम फ़ील्ड के बारे में है, दूसरा पसंदीदा विक्रेता के बारे में है। इसके अलावा मुझे यह मानना ​​है कि खाता आईडी किरायेदार की प्राथमिक कुंजी को संदर्भित करता है; यदि ऐसा है तो आप स्थिरता के लिए TenIID को AccountId का नाम बदलने पर विचार कर सकते हैं।

के बारे में पहले भाग:

कुछ किरायेदारों एक विक्रेता रिकॉर्ड पर कस्टम फ़ील्ड जोड़ना चाहते हैं।

यह कस्टम फ़ील्ड की आवश्यकता के सीमा पर निर्भर करता है। क्या यह सिस्टम के अन्य क्षेत्रों में आवश्यक है। यदि ऐसा है तो यह मोंगोडीबी जैसे नोएसक्यूएल डेटाबेस के लाभों में से एक है।

public class TenantVendorCustomField 
{ 
    [Key] 
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)] 
    public int Id {get; set;} 
    public int AccountId { get;set;} 
    public int VendorId{ get;set;} 
    public string FieldName { get; set; } 
    public string Value {get; set; } 

    [ForeignKey("AccountId")] 
    public virtual Tenant Tenant { get; set; } 

    [ForeignKey("VendorId")] 
    public virtual Vendor Vendor { get; set; } 

} 

पसंदीदा विक्रेताओं के बारे में अगले भाग:: मैं एक TenantVendorCustomField तालिका जोड़ना होगा अनुकूलित क्षेत्रों यह एक ऐसा क्षेत्र में बस रहे हैं

लेकिन मैं सभी पसंदीदा विक्रेताओं लाने के लिए है

मैं वास्तव में यहां व्यवसाय की आवश्यकता के बारे में अधिक जानना चाहता हूं। क्या हर किरायेदार को पसंदीदा विक्रेता होना चाहिए? क्या किरायेदारों के पास एक से अधिक पसंदीदा विक्रेता हो सकते हैं?

public class TenantVendor 
{ 
    public int AccountId { get;set;} 
    public int VendorId{ get;set;} 
    public string NickName { get; set; } 
    public bool Favorite {get; set;} 
} 

var dbVendorQuery = dbContext.TenantVendors 
    .Include(x => x.Vendor) 
    .Where(x => x.TenantVendor.Favorite && x.TenantVendor.AccountId == _account.Id) ; 
:

इन उत्तरों के आधार पर पसंदीदा TenantVendor की संपत्ति हो सकता है

संबंधित मुद्दे