2011-11-24 3 views
0

나는 이것이 간단해야한다고 생각하지만, NHibernate의 간단한 것들은 항상 가장 복잡하다.Fluent NHibernate, HasManytoMany 및 Primary Key issue

public class Foo1 
{ 
//other properties 
public virtual IList<Foo2> Foo2s {get;set;} 
} 
public class Foo2 
{ 
//other properties 
public virtual IList<Foo1> Foo1s {get;set;} 
} 

그리고 매핑 :

나는 두 HasManyToMany 통해 서로 참조 포항 강판이 올바르게 작성되는 테이블을 가입

class Foo1Map : ClassMap<Foo1> 
{ 
//other mappings 
HasManyToMany(c => c.Foo2s); 
} 
class Foo2Map : ClassMap<Foo2> 
{ 
//other mappings 
HasManyToMany(c => c.Foo1s); 
} 

를 그것으로 외래 키에있는 2 개 필드를 갖는다 각각의 테이블, 괜찮아요, 큰 문제는 그 두 필드가 기본 키 (또는 적어도 고유하지 않아야한다는 것입니다). 나는 HasManyToMany에 연결된 다양한 유창한 방법으로 놀았지만 어떤 결과도 얻지 못했습니다.

생성 된 manytomany 테이블이 사용자 정의 POCO를 생성하고 복합 키로 매핑하지 않고도 2 개의 외래 키 필드에 기본 키를 갖게하려면 어떻게해야합니까?

감사합니다.

답변

3

고유 제한 조건도 지수는

class Foo1Map : ClassMap<Foo1> 
{ 
    //other mappings 
    HasManyToMany(c => c.Foo2s) 
     .ParentKeyColumns.Add("foo1_id", p => p.UniqueKey("unique_constraint1").Index("someIndex")) 
     .ChildKeyColumns.Add("foo2_id", p => p.UniqueKey("unique_constraint1")); 
} 

업데이트 : 나 좋은하지 hasMany의 (나는이 프로젝트에 사용 된 같은 코드)에 대한 규칙 만 작업 등

public class IndexOneToManyColumnsConvention : IHasManyConvention 
{ 
    public void Apply(IOneToManyCollectionInstance instance) 
    { 
     var mappingfield = instance.Key.Columns.First().GetType() 
      .GetField("mapping", BindingFlags.Instance | BindingFlags.NonPublic); 

     var columnMapping = (ColumnMapping)mappingfield.GetValue(instance.Key.Columns.First()); 

     if (!columnMapping.HasValue(c => c.Index)) 
     { 
      var typename = instance.Member.DeclaringType.Name; 

      columnMapping.Index = string.Format("index_{0}_{1}", 
       typename.ToLower(), instance.Member.Name.ToLower()); 
     } 
    } 
} 

나는이 해킹을 없애기 위해 FNH의 트렁크에 코드가 있다고 생각한다.

+0

이후 3 년 동안이 필드가 더 안전한 방식으로 처리되었는지 확인하십시오. 이후? 그렇지 않으면, 정보 주셔서 감사합니다. – Ted

+0

@Ted 알 수 없습니다. NHibernate가 MappingByCode를 도입 한 이래로 프로젝트가 유지 관리 모드에 있기 때문에 존재하지 않는다면 곧 존재할 것입니다. – Firo

+0

정보 @Firo 주셔서 감사합니다. – Ted

1

나는 유창한 한계에 부딪쳤다. 그리고 나는 그것을 사용하는 더 진보 된 스키마 비틀기를 설정하는 것을 포기했다. 조회 테이블에 인덱스를 설정하는 두통이 있었기 때문에 SQL을 포스트 작성 스크립트에 추가했습니다.

우리는 NHibernate를 사용하여 데이터베이스를 생성 한 데이터베이스 생성 프로젝트를 사용하여 우리가 사용하는 인덱스와 저장 프로 시저를 생성하는 셋업 포스트 생성 스크립트를 실행합니다.

나는 이것이 당신의 질문에 직접적으로 대답하지 않는다는 것을 알고 있지만 어제이 문제에 어려움을 겪고있었습니다. 그래서 당신이 머리를 잡기로 결심했다면 당신에게 머리를 뻗어 줄 해결책과 약간의 코드를 나누겠다고 생각했습니다. 하위.

다른 사람들이 여기서 한 일을 흥미롭게 보아라.

private void ExecuteScripts(string dir, bool useTransaction = true, bool useMasterConnection = false) 
{ 
    foreach (var file in SqlFiles.Where(x => x.Contains(dir))) 
    { 
     var resource = file.Substring((Assembly.GetExecutingAssembly().GetName().Name + ".scripts.").Length);    

     if (useTransaction) 
      ExecuteSqlWithTransaction(resource, useMasterConnection); 
     else 
      ExecuteSqlWithoutTransaction(resource, useMasterConnection); 
    } 
} 



private void ExecuteSqlWithoutTransaction(string sqlFile, bool useMasterConnection = false) 
     { 
      var sql = string.Empty; 

      var stream = Assembly.GetExecutingAssembly().GetManifestResourceStream((Assembly.GetExecutingAssembly().GetName().Name + ".scripts.") + sqlFile.Replace('\\', '.')); 

      using (var reader = new StreamReader(stream)) 
      { 
       sql = reader.ReadToEnd(); 
      } 

      // replace the [[[dbName]]] and [[[SQLDATAFILEPATH]]] with ACTUAL DB settings we want to work with 
      sql = sql.Replace("[[[DBNAME]]]", DbName); 
      sql = sql.Replace("[[[SQLDATAFILEPATH]]]", SqlDataFilePath); 

      var regex = new Regex("^GO", RegexOptions.IgnoreCase | RegexOptions.Multiline); 
      var lines = regex.Split(sql); 

      var currentConnection = (useMasterConnection) ? MasterSqlConnection : SqlConnection; 

      using (var cmd = currentConnection.CreateCommand()) 
      { 
       cmd.Connection = currentConnection; 

       foreach (var line in lines) 
       { 
        if (line.Length > 0) 
        { 
         cmd.CommandText = line; 
         cmd.CommandType = CommandType.Text; 

         try 
         { 
          cmd.ExecuteNonQuery(); 
         } 
         catch (SqlException ex) 
         { 
          //ShowInfo("Error running script " + sqlFile + " Error: " + ex.Message); 
          throw new Exception(ex.Message); 
         } 
        } 
       } 
      } 

     } 



ALTER TABLE [dbo].[ArticleProjectAssignments] ADD CONSTRAINT [pk_ArticleProjectAssignments] PRIMARY KEY CLUSTERED 
(
    [ArticleId] ASC, 
    [ProjectId] ASC 
) 
GO 
+0

확실히 주목할만한 해결책이다. 나는 그것을 시험해 볼 시간/자원이 없다. 보통 NHibernate를 사용하지 않는다.이 프로젝트에서이 프로젝트를 사용하도록 강요 당했고, 그렇지 않으면 나는 훨씬 더 고급이고 사용하기 쉬운 모든 EF Code First 4.1이다. , 등등. 답장을 보내 주셔서 감사합니다. –

+0

@MatteoMosca는 관심을 가지지 않고 EF 자체적으로 기본 키를 만들거나 어떻게하도록 지시합니까? – Firo

+0

EF는 필자의 예처럼 자동 생성 된 다 대다 테이블에 기본 키를 자동으로 넣습니다. 나는 이것이 옳은 것이라고 생각합니다. 프라이 머리 키가 many-to-many 테이블의 유일한 2 필드에 있지 않아야하는 이유는 없습니다. "다 대다"이지만 다른 필드가있는 테이블의 경우에는 다른 점이 있습니다.이 경우에는 POCO가 매핑됩니다. –