1

オブジェクトをデータベースに永続化しようとしています。この操作は2つのテーブルに触れる必要があります。

[HttpPost]
public ActionResult Create(Report report)
{
    try
    {
        report.Positions = new Iesi.Collections.Generic.HashedSet<Position>();
        var desks = this.session.Query<Desk>().ToList();

        foreach (var desk in desks)
        {
            foreach (var comm in desk.Commodities)
            {
                report.Positions.Add(
                    new Position
                        {
                            Report = report,
                            ReportId = report.Id,
                            Desk = desk,
                            DeskId = desk.Id,
                            Commodity = comm,
                            CommodityId = comm.Id,
                            Value = .0
                        });
            }
        }

        this.session.Save(report);
        return this.RedirectToAction("Index");
    }
    catch
    {
        // some handling
        return this.RedirectToAction("Index");
    }
}

これは私のマッピングです:

public class EntityMapping<TKey, TEntity> : ClassMapping<TEntity>
    where TEntity : Entity<TKey>
{
    public EntityMapping()
    {
        this.Id(x => x.Id, mapper => mapper.Generator(Generators.GuidComb));
    }
}

public class PositionMapping : ClassMapping<Position>
{
    public PositionMapping()
    {
        this.Table("REPORTPOSITIONS");
        this.ComposedId(
            x =>
            {
                x.Property(p => p.ReportId);
                x.Property(p => p.DeskId);
                x.Property(p => p.CommodityId);
            });
        this.Version(x => x.Version, mapper => mapper.Generated(VersionGeneration.Always));
        this.Property(x => x.Value, mapper => mapper.Column("Position"));
    }
}

public class ReportMapping : EntityMapping<Guid, Report>
{
    public ReportMapping()
    {
        this.Table("REPORTS");
        this.Property(x => x.ReportDate, mapper => mapper.Type(NHibernateUtil.Date));
        this.Set(
            x => x.Positions,
            mapper =>
            {
                mapper.Key(km => km.Column("ReportId"));
                mapper.Lazy(CollectionLazy.Lazy);
                mapper.Inverse(true);
                mapper.Cascade(Cascade.All | Cascade.DeleteOrphans);
            },
            rel => rel.OneToMany());
    }
}

これはnhibernateによって使用されるSQLです:

INSERT INTO REPORTS
        (ReportDate,
         Id)
VALUES  ('2012-06-11T00:00:00.00' /* @p0_0 */,
         '7f4d8f3d-1175-4713-bd1c-a06d00bfc614' /* @p1_0 */)

INSERT INTO REPORTPOSITIONS
        (Position,
         CommodityId,
         DeskId,
         ReportId)
VALUES  (0 /* @p0_0 */,
         '3a7d80c4-85e9-ba4b-80d2-064f7f0b58b5' /* @p1_0 */,
         'ed7c4e75-7417-a241-a40a-0ff4bfad7172' /* @p2_0 */,
         '00000000-0000-0000-0000-000000000000' /* @p3_0 */)

sqlステートメントのReportIdは、コントローラーアクションで設定していないため、C#のデフォルト(GUID)です。NHibernateはレポートテーブルのIDを生成します。コントローラアクションでIDを設定したとき

report.Id = Guid.NewGuid();

SQLはパラメータとして異なるIDを使用します。

INSERT INTO REPORTS
        (ReportDate,
         Id)
VALUES  ('2012-06-11T00:00:00.00' /* @p0_0 */,
         '6164264e-29cd-4d9c-befd-a06d00c2defd' /* @p1_0 */)

INSERT INTO REPORTPOSITIONS
        (Position,
         CommodityId,
         DeskId,
         ReportId)
VALUES  (0 /* @p0_0 */,
         '3a7d80c4-85e9-ba4b-80d2-064f7f0b58b5' /* @p1_0 */,
         'ed7c4e75-7417-a241-a40a-0ff4bfad7172' /* @p2_0 */,
         '594b2206-7c25-4430-af18-5f2643f6c7bf' /* @p3_0 */)

NHibernateによって生成されたIDを2番目のテーブルに使用するにはどうすればよいですか?

アップデート:

ManyToOneパーツを明示的にマッピングしようとしました

this.ManyToOne(x => x.Report, mapper => mapper.Column("ReportId"));

しかし、これでは、レポート位置に挿入しようとさえしません。

代わりに私がこのようなことをするとき

this.ManyToOne(x => x.Report, mapper => mapper.Column("foo"));

このSQLステートメントを作成します

INSERT INTO REPORTS
        (ReportDate,
         Id)
VALUES  ('2012-06-11T00:00:00.00' /* @p0_0 */,
         '4ff74d49-8749-400c-b079-a06d00e0bee5' /* @p1_0 */)

INSERT INTO REPORTPOSITIONS
        (foo,
         Position,
         CommodityId,
         DeskId,
         ReportId)
VALUES  ('4ff74d49-8749-400c-b079-a06d00e0bee5' /* @p0_0 */,
         0 /* @p1_0 */,
         '3a7d80c4-85e9-ba4b-80d2-064f7f0b58b5' /* @p2_0 */,
         'ed7c4e75-7417-a241-a40a-0ff4bfad7172' /* @p3_0 */,
         '00000000-0000-0000-0000-000000000000' /* @p4_0 */)

これで、fooは正しいキーを持ちます。誰かがこの振る舞いを説明し、解決策を提供してもらえますか?

4

2 に答える 2

2

私はおそらくそれを複合要素としてマッピングし、idの問題全体を取り除きます。チェックしたい場合は、一意の制約を作成できます。

this.Set(
        x => x.Positions,
        mapper =>
        {
            mapper.Key(km => km.Column(c => 
            {
              c.Name("ReportId");
              c.UniqueKey("ReportDeskCommodity");
            }));
            mapper.Lazy(CollectionLazy.Lazy);
        },
        rel => rel.Component(comp => 
        {
            comp.Parent(p => p.Report);

            comp.Property(
              p => p.DeskId, 
              m => m.Column(c => c.UniqueKey("ReportDeskCommodity")));

            comp.Property(
              p => p.CommodityId, 
              m => m.Column(c => c.UniqueKey("ReportDeskCommodity")));

            comp.Property(
              x => x.Value, 
              m => m.Column("Position"));
        }));

キーをマップする正当な理由がない場合は、実際には多対1にすることができます。これは、ドメインモデルの変更です。

        rel => rel.Component(comp => 
        {
            comp.Parent(p => p.Report);

            comp.ManyToOne(
              p => p.Desk, 
              m => m.Column(c => 
              {
                c.Name("DeskId");
                c.UniqueKey("ReportDeskCommodity");
              }));


            comp.ManyToOne(
              p => p.Commodity, 
              m => m.Column(c => 
              {
                c.Name("CommodityId");
                c.UniqueKey("ReportDeskCommodity");
              }));

            comp.Property(
              x => x.Value, 
              m => m.Column("Position"));
        }));
于 2012-06-11T10:14:38.493 に答える
0

NHibernatesの急な学習曲線をいじって登った後、私はこの解決策を思いつきました。

public class PositionMapping : ClassMapping<Position>
{
    public PositionMapping()
    {
        this.Table("REPORTPOSITIONS");
        this.ComposedId(
            x =>
            {
                x.ManyToOne(p => p.Report, mapper => mapper.Column("ReportId"));
                x.ManyToOne(p => p.Desk, mapper => mapper.Column("DeskId"));
                x.ManyToOne(p => p.Commodity, mapper => mapper.Column("CommodityId"));
            });
        this.Version(x => x.Version, mapper => mapper.Generated(VersionGeneration.Always));
        this.Property(x => x.Value, mapper => mapper.Column("Position"));
    }
}

ComposedIdパーツをManyToOneとして宣言し、PositionエンティティからGuidプロパティを削除しました。NHibernateは、テーブルREPORTPOSITIONSに従って、PositionエンティティのReport、Desk、およびCommodityプロパティにデータを入力し、すべてのPositionをこのテーブルに永続化するようになりました。

于 2012-06-12T05:59:45.077 に答える