NHibernate اقترانات متعددة إلى متعددة مما يجعل كلا الطرفين كأصل باستخدام كيان العلاقة في نموذج المجال

StackOverflow https://stackoverflow.com/questions/1928591

سؤال

جهات:فريق <-> فريق العمل <-> موظف

متطلبات:

  • يمكن أن يوجد فريق وموظف بدون نظيره.
  • في العلاقة بين الفريق والموظف يكون الفريق مسؤولاً (الوالد) [باستخدام TeamRepository لاحقًا].
  • في العلاقة بين الموظف وفريق العمل، يكون الموظف هو المسؤول (والده) [باستخدام مستودع الموظفين لاحقًا].
  • التكرارات غير مسموح بها.
  • يؤدي حذف فريق إلى حذف جميع الموظفين في الفريق، إذا لم يكن الموظف في فريق آخر.
  • يؤدي حذف الموظف إلى حذف الفريق فقط، إذا لم يكن الفريق يحتوي على المزيد من الموظفين.

رسم الخرائط:

public class TeamMap : ClassMap<Team>
{
    public TeamMap()
    {
        // identity mapping
        Id(p => p.Id)
            .Column("TeamID")
            .GeneratedBy.Identity();

        // column mapping
        Map(p => p.Name);

        // associations
        HasMany(p => p.TeamEmployees)
            .KeyColumn("TeamID")
            .Inverse()
            .Cascade.SaveUpdate()
            .AsSet()
            .LazyLoad();
    }
}

public class EmployeeMap : ClassMap<Employee>
{
    public EmployeeMap()
    {
        // identifier mapping
        Id(p => p.Id)
            .Column("EmployeeID")
            .GeneratedBy.Identity();

        // column mapping
        Map(p => p.EMail);
        Map(p => p.LastName);
        Map(p => p.FirstName);

        // associations
        HasMany(p => p.TeamEmployees)
            .Inverse()
            .Cascade.SaveUpdate()
            .KeyColumn("EmployeeID")
            .AsSet()
            .LazyLoad();

        HasMany(p => p.LoanedItems)
            .Cascade.SaveUpdate()
            .LazyLoad()
            .KeyColumn("EmployeeID");
    }
}

public class TeamEmployeeMap : ClassMap<TeamEmployee>
{
    public TeamEmployeeMap()
    {
        Id(p => p.Id);

        References(p => p.Employee)
            .Column("EmployeeID")
            .LazyLoad();

        References(p => p.Team)
            .Column("TeamID")
            .LazyLoad();
    }
}

تكوين الموظفين وفرق العمل:

    var employee1 = new Employee { EMail = "Mail", FirstName = "Firstname", LastName = "Lastname" };
    var team1 = new Team { Name = "Team1" };
    var team2 = new Team { Name = "Team2" };

    employee1.AddTeam(team1);
    employee1.AddTeam(team2);


    var employee2 = new Employee { EMail = "Mail2", FirstName = "Firstname2", LastName = "Lastname2" };
    var team3 = new Team { Name = "Team3" };

    employee2.AddTeam(team3);
    employee2.AddTeam(team1);

    team1.AddEmployee(employee1);
    team1.AddEmployee(employee2);
    team2.AddEmployee(employee1);
    team3.AddEmployee(employee2);

    session.SaveOrUpdate(team1);
    session.SaveOrUpdate(team2);
    session.SaveOrUpdate(team3);

    session.SaveOrUpdate(employee1);
    session.SaveOrUpdate(employee2);

بعد ذلك أقوم بالتغييرات باستخدام المعاملة.Commit().أول شيء غريب هو أنه يجب علي حفظ الفرق والموظفين بدلاً من واحد منهم فقط (لماذا؟!).إذا قمت فقط بحفظ جميع الفرق أو (Xor) جميع الموظفين، فسأحصل على TransientObjectException:

"يشير الكائن إلى مثيل عابر غير محفوظ - احفظ المثيل العابر قبل التدفق.يكتب:core.domain.model.employee ، الكيان:المجال الأساسي.النموذج.الموظف"

عندما أقوم بحفظ جميع الفرق والموظفين الذين تم إنشاؤهم، يتم حفظ كل شيء بشكل جيد، ولكن جدول العلاقات TeamEmployee موجود الجمعيات المكررة.

ID EID TID
1  1   1
2  2   1
3  1   2
4  2   3
5  1   1
6  1   2
7  2   3
8  2   1

لذلك بدلاً من 4 علاقات هناك 8 علاقات.4 علاقات للجانب الأيسر و 4 علاقات للجانب الأيمن.:[

ماذا أخطئ؟

مزيد من الأسئلة:عندما أقوم بحذف فريق أو موظف، هل يجب علي إزالة الفريق أو الموظف من قائمة TeamEmployee في نموذج الكائن أم أن NHibernate يقوم بالمهمة نيابةً عني (باستخدام session.delete(..))؟

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

المحلول

أنت تتحدث عن منطق الأعمال.ليس غرض NHibernate تنفيذ منطق العمل.

ما يفعله الكود الخاص بك:

لقد قمت بتعيين مجموعتين مختلفتين من TeamEmployeeس، واحد في Team, ، واحد في Employee.في التعليمات البرمجية الخاصة بك، يمكنك إضافة عناصر إلى كلتا المجموعتين، مما يؤدي إلى إنشاء مثيلات جديدة لـ TeamEmployee كل مرة.فلماذا تتوقع ألا يقوم NHibernate بتخزين كل هذه الحالات المميزة؟

ما يمكنك القيام به لإصلاحه:

أجريتها TeamEmployee كيان (على عكس نوع القيمة).لإنشاء مثيل مرة واحدة فقط، سيتعين عليك إنشاء مثيل له مرة واحدة فقط في الذاكرة وإعادة استخدامه في كلتا المجموعتين.افعل ذلك فقط عندما تحتاج حقًا إلى هذا الفصل في نموذج المجال الخاص بك.(على سبيل المثال.لأنه يحتوي على معلومات إضافية حول العلاقات وهو في الواقع كيان قائم بذاته.)

إذا لم تكن بحاجة إلى الفصل، فمن الأسهل بكثير تعيينه كعلاقة متعدد إلى متعدد (كما اقترحه بالفعل كريس كونواي).نظرًا لوجود مجموعتين في الذاكرة من المتوقع أن تحتويا على نفس البيانات، فإنك تطلب من NHibernate أن يتجاهل إحداهما عند التخزين، وذلك باستخدام Inverse.

الوالد على كلا الطرفين المشكلة

لا يوجد الوالدين من كلا الطرفين.أعتقد أنه من الواضح أنه لا الفريق ولا الموظف هو أحد الوالدين للآخر، فهما مستقلان.ربما تقصد أنهما والدا المستوى المتوسط TeamEmployee.لا يمكن أن يكونوا الوالدين (وبالتالي المالك) لنفس المثيل.إما أن يكون أحدهما هو الوالد، أو أنه مثيل مستقل آخر، مما يجعل إدارته أكثر تعقيدًا (هذه هي الطريقة التي نفذتها بها الآن).إذا قمت بتعيينها كعلاقة متعدد إلى متعدد، فستتم إدارتها بواسطة NHibernate.

يجب القيام به وفقًا لمنطق عملك:

  • تخزين الفرق الجديدة والموظفين الجدد
  • إدارة العلاقات والحفاظ على تزامنها
  • حذف الفرق والموظفين عند عدم استخدامها بعد الآن.(لا يوجد صراحة جمع القمامة المستمر التنفيذ في NHibernate، لعدة أسباب.)

نصائح أخرى

يبدو أنك بحاجة إلى HasManyToMany بدلاً من خريطتين HasMany.أيضًا، ليست هناك حاجة إلى TeamEmployeeMap إلا إذا كان لديك خاصية أخرى في هذا الجدول تحتاج إلى تعيين.شيء آخر، يحتاج جانب واحد فقط إلى تعيين Inverse() وبما أنك تضيف فرقًا إلى الموظفين، أعتقد أنك بحاجة إلى جعل TeamMap معكوسًا.سيؤدي وجود العكس على جانب واحد فقط إلى التخلص من الإدخالات المكررة في قاعدة البيانات.

ربما شيء من هذا القبيل:

public class TeamMap : ClassMap<Team>
{
    public TeamMap()
    {
        // identity mapping
        Id(p => p.Id)
           .Column("TeamID")
           .GeneratedBy.Identity();

        // column mapping
        Map(p => p.Name);

        // associations
        HasManyToMany(x => x.TeamEmployees)
            .Table("TeamEmployees")
            .ParentKeyColumn("TeamID")
            .ChildKeyColumn("EmployeeID")
            .LazyLoad()
            .Inverse()
            .AsSet();
    }
}

public class EmployeeMap : ClassMap<Employee>
{
    public EmployeeMap()
    {
        // identifier mapping
        Id(p => p.Id)
            .Column("EmployeeID")
            .GeneratedBy.Identity();

        // column mapping
        Map(p => p.EMail);
        Map(p => p.LastName);
        Map(p => p.FirstName);

        // associations
        HasManyToMany(x => x.TeamEmployees)
            .Table("TeamEmployees")
            .ParentKeyColumn("EmployeeID")
            .ChildKeyColumn("TeamID")
            .Cascade.SaveUpdate()
            .LazyLoad()
            .AsSet();

        HasMany(p => p.LoanedItems)
            .Cascade.SaveUpdate()
            .LazyLoad()
            .KeyColumn("EmployeeID");
    }
}

باستخدام هذا، سيؤدي الحذف إلى حذف TeamEmployee من قاعدة البيانات نيابةً عنك.

الدفع هذا البرنامج التعليمي, ، وعلى وجه التحديد كيفية رسم الخرائط بين Product و Store ينصب.

لا يسمح NHibernate بالارتباط بين العديد من الآباء والأمهات في كلا الطرفين.

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