سؤال

لدي قاعدة بيانات بسيطة مكونة من ثلاثة جداول مع علاقة متعدد بمتعدد.

A(id, Name)
B(id, Name)
AB(AId, BId) references A and B

الطبقات المقابلة:

public class A
{
    public virtual int Id { get; set; }
    public virtual string Name { get; set; }
}

public class B
{
    public virtual int Id { get; set; }
    public virtual string Name { get; set; }
}

public class AB
{
    public virtual A A { get; set; }
    public virtual B B { get; set; }
    public override bool Equals(object obj) { /* routine */ }
    public override int GetHashCode() { /* routine */ }
}

لقد قمت بإجراء تعيينات باستخدام Fluent NHibernate:

public class AMap : ClassMap<A>
{
    public AMap()
    {
        Id(x => x.Id).GeneratedBy.Identity();
        Map(x => x.Name);
    }
}

public class BMap : ClassMap<B> { /* The same as for A */ }

public class ABMap : ClassMap<AB>
{
    public ABMap()
    {
        CompositeId()
            .KeyReference(x => x.A, "AId")
            .KeyReference(x => x.B, "BId");
    }
}

والآن أريد أن أكون قادرًا على القيام بشيء كهذا

var a = new A { Name = "a1" };    
var b = new B { Name = "b1" };    
var ab = new AB { A = a, B = b };

//session.SaveOrUpdate(a);
//session.SaveOrUpdate(b);
session.SaveOrUpdate(ab);

ولكن على حفظ أو تحديث أنا أفهم TransientObjectException.لذلك لتمريرها أنا بحاجة إلى ذلك حفظ أو تحديث A وB قبل حفظ AB.ولكن يبدو أنه يجب أن تكون هناك طريقة أخرى للاحتفاظ بهذه الكائنات في مكان واحد حفظ أو تحديث.

هل هناك أي طريقة للإشارة إلى تعيين AB إلى تتالي A و B على عملية الحفظ؟

تحديث:

لقد قمت بإزالة قائمة روابط AB في الفصل الدراسي من أجل الوضوح.في الأصل كان:

public class A
{
    public A()
    {
        LinkToB = new List<AB>();
    }

    public virtual int Id { get; set; }
    public virtual string Name { get; set }
    public virtual IList<AB> LinkToB { get; private set; }
}

public class AMap : ClassMap<A>
{
    public AMap()
    {
        Id(x => x.Id).GeneratedBy.Identity();
        Map(x => x.Name);

        HasMany(x => x.LinkToB)
            .KeyColumn("AId")
            .Inverse()
            .Cascade.All()
            .AsBag();
    }
}

// inside the transaction
var a = new A { Name = "a1" };
var b = new B { Name = "b1" };

a.LinkToB.Add(new AB { A = a, B = b });
// session.SaveOrUpdate(b);
session.SaveOrUpdate(a);

شكرًا لك!

هل كانت مفيدة؟

المحلول

لقد طرحت هذا السؤال في مجموعة مستخدمي nhibernate.وكان الجواب أنه لا توجد طريقة لتسلسل أي عملية باستخدام المعرف المركب (ربما يكون ذلك ممكنًا في الإصدارات المستقبلية).

لذلك قمت بعمل حل بديل.لقد قمت بوضع مرجعين (متعدد إلى واحد مع تتالي) بدلاً من CompositeId وأضفت معرفًا إلى جدول AB وكيان AB.وهي الآن تعمل والكيانات A وB متتالية.

نصائح أخرى

مجرد ملاحظة جانبية، ولكن لماذا قمت بإنشاء فئة AB؟إذا كانت العلاقة بين هاتين الفئتين لا تحتوي على أي خصائص إضافية، فإن فئتك "AB" ليست ضرورية ...

للإجابة على سؤالك:يمكنك تحديد خيارات التتالي على العلاقة في NHibernate.

في Fluent NHibernate، أعتقد أنه سيتعين عليك القيام بذلك على النحو التالي:

public class FooMap : ClassMap<Foo>
{
    public FooMap()
    {
       HasMany(x => x.Bars).Cascade.AllDeleteOrphan();
    }
}

(لاحظ أنه يتعين عليك تطبيقه على موقفك، لكن تعيين المجموعة يُرجع خاصية Cascade، حتى تتمكن من تحديد التقنية المتتالية التي ترغب في تطبيقها)

لقد تمكنت بالفعل من تشغيله بسهولة شديدة، ويبدو الرمز غير جاف جدًا!

إليكم ما تبدو عليه حالتي:

public class MappingSample : ClassMap<DomainClass>
{
    public MappingCvTheme()
    {
        CompositeId()
            .KeyProperty(x => x.SomeProperty)
            .KeyReference(x => x.SomeReferencedObjectProperty);

        //here comes the trick, repeat the reference code:
        References(x => x.SomeReferencedObjectProperty).Cascade.All();
    }
}

آمل أن يساعد شخص ما يبحث عن نفس المشكلة في المستقبل.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top