views:

336

answers:

4

How can I implement the so called "repository pattern" that Rob Conery shows in [MVC Storefront][1] when I use two different generated linq codes? Do I need to implement a real repository pattern as Fredrik Normen discusses at What purpose does the Repository Pattern have?? The thing is that I want pass some of the nice features that LINQ provides from my "repository" so that I can use it later, so if not required I do not want to implement a real repository pattern as Fredrik discussed about.

Now to my problem. I have downloaded [dblinq ][3] which is a Linq Provider for MySql, Oracle and PostgreSQL. In my project I have now generated LINQ code for MySQL and SQL(microsoft). The problem is that they both need to generate classes with same names but with somewhat different content. Can I use somehow implement this with namespaces or something so that I can be able to use them both, as is the idea with the "repository pattern"? Example for a Language table SQl

[Table(Name="dbo.Language")]
public partial class Language : INotifyPropertyChanging, INotifyPropertyChanged
{

 private static PropertyChangingEventArgs emptyChangingEventArgs = new PropertyChangingEventArgs(String.Empty);

 private int _Id;

 private string _Name;

 private EntitySet<Book> _Books;

#region Extensibility Method Definitions
partial void OnLoaded();
partial void OnValidate(System.Data.Linq.ChangeAction action);
partial void OnCreated();
partial void OnIdChanging(int value);
partial void OnIdChanged();
partial void OnNameChanging(string value);
partial void OnNameChanged();
#endregion

 public Language()
 {
  this._Books = new EntitySet<Book>(new Action<Book>(this.attach_Books), new Action<Book>(this.detach_Books));
  OnCreated();
 }

 [Column(Storage="_Id", AutoSync=AutoSync.OnInsert, DbType="Int NOT NULL IDENTITY", IsPrimaryKey=true, IsDbGenerated=true)]
 public int Id
 {
  get
  {
   return this._Id;
  }
  set
  {
   if ((this._Id != value))
   {
    this.OnIdChanging(value);
    this.SendPropertyChanging();
    this._Id = value;
    this.SendPropertyChanged("Id");
    this.OnIdChanged();
   }
  }
 }

 [Column(Storage="_Name", DbType="NVarChar(100) NOT NULL", CanBeNull=false)]
 public string Name
 {
  get
  {
   return this._Name;
  }
  set
  {
   if ((this._Name != value))
   {
    this.OnNameChanging(value);
    this.SendPropertyChanging();
    this._Name = value;
    this.SendPropertyChanged("Name");
    this.OnNameChanged();
   }
  }
 }

 [Association(Name="Language_Book", Storage="_Books", ThisKey="Id", OtherKey="Language")]
 public EntitySet<Book> Books
 {
  get
  {
   return this._Books;
  }
  set
  {
   this._Books.Assign(value);
  }
 }

 public event PropertyChangingEventHandler PropertyChanging;

 public event PropertyChangedEventHandler PropertyChanged;

 protected virtual void SendPropertyChanging()
 {
  if ((this.PropertyChanging != null))
  {
   this.PropertyChanging(this, emptyChangingEventArgs);
  }
 }

 protected virtual void SendPropertyChanged(String propertyName)
 {
  if ((this.PropertyChanged != null))
  {
   this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
  }
 }

 private void attach_Books(Book entity)
 {
  this.SendPropertyChanging();
  entity.Language1 = this;
 }

 private void detach_Books(Book entity)
 {
  this.SendPropertyChanging();
  entity.Language1 = null;
 }
}

MySQL

    [Table(Name = "asp.Language")]
public partial class Language : INotifyPropertyChanged
{
 #region INotifyPropertyChanged handling

 public event PropertyChangedEventHandler PropertyChanged;

 protected virtual void OnPropertyChanged(string propertyName)
 {
  if (PropertyChanged != null)
  {
   PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
  }
 }

 #endregion

 #region int ID

 private int _id;
 [DebuggerNonUserCode]
 [Column(Storage = "_id", Name = "Id", DbType = "int", IsPrimaryKey = true, IsDbGenerated = true, CanBeNull = false)]
 public int ID
 {
  get
  {
   return _id;
  }
  set
  {
   if (value != _id)
   {
    _id = value;
    OnPropertyChanged("ID");
   }
  }
 }

 #endregion

 #region string Name

 private string _name;
 [DebuggerNonUserCode]
 [Column(Storage = "_name", Name = "Name", DbType = "varchar(100)", CanBeNull = false)]
 public string Name
 {
  get
  {
   return _name;
  }
  set
  {
   if (value != _name)
   {
    _name = value;
    OnPropertyChanged("Name");
   }
  }
 }

 #endregion

 #region Children

 private EntitySet<Book> _book;
 [Association(Storage = "_book", OtherKey = "Language", ThisKey = "ID", Name = "Book_ibfk_1")]
 [DebuggerNonUserCode]
 public EntitySet<Book> Book
 {
  get
  {
   return _book;
  }
  set
  {
   _book = value;
  }
 }


 #endregion

 #region Attachement handlers

 private void Book_Attach(Book entity)
 {
  entity.LanguageLanguage = this;
 }

 private void Book_Detach(Book entity)
 {
  entity.LanguageLanguage = null;
 }


 #endregion

 #region ctor

 public Language()
 {
  _book = new EntitySet<Book>(Book_Attach, Book_Detach);
 }

 #endregion

}
+1  A: 

This is a little offtopic but it might help.

If you're using Linq, repositories, MySql and MS Sql, and Rob Connery's advice you might as well use SubSonic 3 and make your life a little easier.

Here is a 5 minute demo: http://subsonicproject.com/docs/Simple_Repo_5_Minute_Demo

adolfojp
Thank you for the answer. SubSonic does indeed look promising. But I want to learn more about .net before I start to using something like that (I have just tried .net for one week now).
unkown
A: 

I'am in the same situation than you, i'm using linq to sql, but in the future i want to try the entity framework, and i will do.

For what i saw, the solution of that is use dependency injection and an ioc container (if you are not using it, take a look, may seem hard but is very easy and interesting). Most of the examples of that, creates an interface for each repository and then with the ioc configuration file you can choose what do you whant to use.

For example, you have an ICustomersRepository, that is what you might use in your controllers, and a SQLCustomersRepository and a EntityCustomersRepository, that you can swap only changing the configuration file.

As you said the problem is the entities with the same name... the solution is to use the same pattern for the entities, create an interface for each entity and use the ioc container. I know this is tedius, what i would do is create a T4 Template that create the interfaces for each entities automatically and then replace the T4 templates, that use LinqToSQL and the entiy Framework for implement it... yes is a lot of work.

For an introduction of T4 take a look at this video, http://msdn.microsoft.com/en-us/vstudio/cc308634.aspx

Alfredo Fernández
A: 

I would suggest an entity namespace for your BO, such as MyCompany.MyApp.Entities.

You can then change the Entity Namespace property of each DBML to generate your entities within this. If your using more than one DBML for the same types, you will need to have a separate namespace for each DBML, such as MyCompany.MyApp.Entities.MySql)

If you need classes for more than one type of database/data-access platform upfront, I suggest you create abstract base classes that your entities can make concrete, and an abstract repository to do the data access.

In my own experience I recently created an abstract LinqToSqlRepostory, and then extended this for my major business objects.

MattH
+1  A: 

Ideally, you would create each class only once and the database differences should be taken care of by the ORM (this is how NHibernate and Subsonic work).

If you really need different classes for each database, then yes, you can have classes with the same name as long as they are in different namespaces. If you are writing the code for the classes yourself this is very easy:

// C# sample
namespace MyCompany.MyApp.Entities.Oracle
{
    public class MyClass
    {
    // ...
    }
}

namespace MyCompany.MyApp.Entities.SqlServer
{
    public class MyClass
    {
    // ...
    }
}

If the classes are being auto-generated, you should check in the code generation tool how to specify namespaces. For example, with LINQ to SQL designer, you can specify the namespace in the table/class properties, or by editing the DBML file yourself.

Lucas