I work on a project where we was using SqlConnection, SqlCommand and plain SQL to access repository. Now, I am trying to migrate to Linq2Sql and I want to use the same models. How can I achieve this?
I will reduce the project structure to the minimal meaningful example.
Let's say I have the following classes:
namespace Model
{
public class User
{
public int Id { get; set; }
}
}
All models in Model namespace are one-in-one copy of database entities.
namespace Repository
{
public class UserRepository
{
private _sqlConnectionHelper = new SqlConnectionHelper();
public User GetUser()
{
var reader = _sqlConnectionHelper
.ExecuteAndReturnReader("SELECT * FROM [dbo].[Users]");
while (reader.Read())
{
return new User
{
Id = (int)reader["Id"]
};
}
return null;
}
}
}
Now I am trying to migrate to Linq2Sql. I have created a MyContext.dmbl file with User table in Repository project. It has generated the following class:
namespace Repository
{
[global::System.Data.Linq.Mapping.TableAttribute(Name="dbo.Users")]
[global::System.Runtime.Serialization.DataContractAttribute()]
public partial class User: INotifyPropertyChanging, INotifyPropertyChanged
{
private int _ID;
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();
}
}
}
// Some other methods
}
}
Now, the problem is that I have a lot of of entities, repositories, models etc. I don't want to change the whole project to use new generated models but not mine from Model namespace. How can I make Linq2Sql work with my models?
It also affects my architecture because in case of these models, the entity and the repository is the same object. I don't need my entities to be CRUD objects. I just want to make minimal changes to project and only use convenient LINQ requests instead of plain SQL like this:
namespace Repository
{
public class UserRepository
{
private MyContextDataContext _myContext = new MyContextDataContext();
public User GetUser()
{
return _myContext.Users.FirstOrDefault();
}
}
}
Or I just don't understand something about purpose and logic of Linq2Sql and it is how it only works like?
Of course, I can write converters or use reflection and make a copy of object property-by-property but it doesn't sound like a good solution.
Ok. Finally, I have found an answer which is pretty simple - Linq2Sql is not a library I was looking for.
There are different approaches for object-relational mapping: code-first, database-first, model-first.
Here is the good StackOverflow article about their differences.
Now, when I learned it, what I have described in my question could be easily rephrased as "how can I make Linq2Sql be code-first". The answer is simple - I cannot do this.
As a result of some investigations, I have understood that I was looking for Entity Framework which perfectly fit in my project.
Now, my repository looks like this:
namespace Repository
{
public MyContextDataContext : DbContext
{
public DbSet<User> Users { get; set; }
}
public class UserRepository
{
private MyContextDataContext _myContext = new MyContextDataContext();
public User GetUser()
{
return _myContext.Users.FirstOrDefault();
}
}
}
Related
I am creating a MS Web API 2 project. I have created my Entity Framework in a separate project and am referencing it in my API. Reading over a few tutorials, it is suggested that:
"ideally, we should not return EF entity objects from the Web API. It is recommended to return DTO (Data Transfer Object) from Web API".
Hence, I have created my model in my API:
namespace MyAPI.Models
{
[Table("Customer")]
public class CustomerViewModel
{
[Key]
public int CustomerID { get; set; }
public string Code { get; set; }
public string Name { get; set; }
}
}
My question is: Do I need to create a data context class for each model in my API or is it fine to use EF context class? And if I do need to create a separate context for each model, how can I achieve this by a reference to the EF context class? Below is what I have started with:
namespace MyAPI.Models
{
public class CustomerDbContext : DbContext
{
public CustomerDbContext() : base("name=CusetomerDbContext")
{
}
public DbSet<MyEFDataAccess.Customer> CustomerViewModel { get; set; }
}
}
And my Controller is:
namespace MyAPI.Controllers
{
public class CustomersController : ApiController
{
private readonly CustomerDbContext _context = new CustomerDbContext();
// GET: api/Customer
public IQueryable<CustomerViewModel> GetCustomerViewModels()
{
return _context.CustomerViewModel;
}
}
The above correctly throws an error because it cannot convert EF customer to CustomerViewModel directly!
ideally, we should not return EF entity objects from the Web API. It
is recommended to return DTO (Data Transfer Object) from Web API.
The reason for this is to make sure you can change your DB schema without changing API, and vice versa. If you accomplish that goal, then you've adhered to that given advice.
The problem you're having is basic. Type A cannot be implicitly converted to Type B. As far as the compiler is concerned, you're trying to convert a DbContext to a FormControl, and it has no idea how to do that. You need to tell it explicitly what to do. One example, albeit not great:
public DbSet<MyEFDataAccess.Customer> Customer { get; set; }
and
public IQueryable<CustomerViewModel> GetCustomerViewModels()
{
return _context.Customer.Select(
customer => new CustomerViewModel
{
// <assign properties here>
}
);
}
That being said, returning an IQueryable<T> from your Controller is a definite no-no. You definitely want to allow for the consumer to query specific records. You could do this to enable pagination, for instance:
public async Task<List<CustomerViewModel>> GetCustomerViewModels(
int skip = 0,
int take = 100
)
{
return await _context.Customer
.Skip(skip)
.Take(take)
.Select(
customer => new CustomerViewModel
{
// <assign properties here>
}
)
.ToListAsync();
}
My project is layered as follows:-
DAL (Entity) --> BLL (DTO) --> ApplicationComponent (ViewModel).
There will be multiple components of application (ApplicationComponent) which will access BLL. Components include windows services, web services, web API and MVC controller.
I am transforming NHibernate Entity objects to DTO objects while passing them from DAL to BLL. While passing this state to ApplicationComponent, BLL again converts it to ViewModel.
This helps me separate the concerns and how data is handled in each layer. I am not in favor of returning NHibernate Entity object to view for following reasons: -
Data get exposed to UI that I want to hide (or only expose if needed) like passwords, user type, permission etc.
On references/joins, NHibernate executes additional queries when property is accessed which nullify the use of lazy loading.
Unnecessary data exposed to user (of Entity) creates confusion and gap for bugs.
Persistence implementations leaking into BLL/UI. Entity is not designed for UI. It cannot serve UI in all cases.
We use attributes on DTO properties for user input validation which looks odd with Entity.
I am facing following problems with this approach: -
Biggest and obvious problem is redundant objects with similar members and functionality.
I have to write mapper methods in each layer to transform object. This could be minimized by using AutoMapper or something similar; but it does not fully resolve problem.
Questions:-
Is this an over separation and should be avoided (at least minimized)?
If this approach is correct, I do not see any simple way to fully bypass two problems I stated above. Please suggest.
If this approach is incorrect, please suggest corrections.
References:-
Link1 suggests to transfer Entity object to view which in my understanding not a good idea.
Link2 suggests to map Entity with DTO that I am already doing.
Link3 does not help.
Link4 suggests using something like auto mapper tools which is OK. But it still does not solve the problem completely.
Link5 is great post. It explains why those should be separate which I agree. It does not comment on how to minimize the overhead caused by it.
Link6 is not helpful again.
Link7 is an excellent answer which suggests use Entity as is in UI if possible. It still does not apply to most of my project.
Linl8 is another excellent resource that suggest to go on mapping two way as I am doing now. It still does not suggest a way to minimize overhead.
Have you considered creating a shared interface between the DTO and the Entity? You should not tightly couple your ORM to the rest of your application. Or in fact use anything other than interfaces between them if at all possible.
You could, in theory, have a separate project that just holds the contract/abstractions of what you expect to be passed around. To minimize mapping overhead and to leave it open for the extension you can ensure that the entity implements the interface as expected (omitting what is not needed), and in cases where you need a bespoke DTO you can create a model with mapping using the interfaces.
There is some overhead when adding extra interface projects but it will keep your code cleaner and more maintainable in the long run.
namespace Data
{
public class FakeRepo : IFakeRepo
{
public IThisIsAnEntity GetEntity()
{
return new ThisIsAnEntity();
}
}
public class ThisIsAnEntity : IThisIsAnEntity
{
public string HiddenField { get; set; }
public long Id { get; set; }
public string SomeField { get; set; }
public string AnotherField { get; set; }
}
}
namespace Data.Abstractions
{
public interface IFakeRepo
{
IThisIsAnEntity GetEntity();
}
}
namespace Abstractions
{
public interface IThisIsAnEntity : IThisIsAnSlimmedDownEntity
{
string SomeField { get; set; }
}
public interface IThisIsAnSlimmedDownEntity
{
long Id { get; set; }
string AnotherField { get; set; }
}
}
namespace Services.Abstractions
{
public interface ISomeBusinessLogic
{
IThisIsAnEntity GetEntity();
IThisIsAnSlimmedDownEntity GetSlimmedDownEntity();
}
}
namespace Services
{
public class SomeBusinessLogic : ISomeBusinessLogic
{
private readonly IFakeRepo _repo;
public SomeBusinessLogic(IFakeRepo repo)
{
_repo = repo;
}
public IThisIsAnEntity GetEntity()
{
return _repo.GetEntity();
}
public IThisIsAnSlimmedDownEntity GetSlimmedDownEntity()
{
return _repo.GetEntity();
}
}
}
namespace UI
{
public class SomeUi
{
private readonly ISomeBusinessLogic _service;
public SomeUi(ISomeBusinessLogic service)
{
_service = service;
}
public IThisIsAnSlimmedDownEntity GetViewModel()
{
return _service.GetSlimmedDownEntity();
}
public IComposite GetCompositeViewModel()
{
var dto = _service.GetSlimmedDownEntity();
var viewModel = Mapper.Map<IThisIsAnSlimmedDownEntity, IComposite>(dto);
viewModel.SomethingSpecial = "Something else";
return viewModel;
}
}
public class SomeViewModel : IComposite
{
public long Id { get; set; }
public string AnotherField { get; set; }
public string SomethingSpecial { get; set; }
}
}
namespace UI.Abstractions
{
public interface IComposite : IThisIsAnSlimmedDownEntity, ISomeExtraInfo
{
}
public interface ISomeExtraInfo
{
string SomethingSpecial { get; set; }
}
}
nhibernate is one of those orm`s that allow you to avoid having DAL entities and it will be better for performance to avoid extra mapping from BLL TO DAL, but if it is not critical for you, it will be better to keep it at as it is to have application layers loose coupled
Like I mentioned in this question, I wanted to rename some auto generated properties.
So I use the following partial class
public partial class Plan
{
public Profile Creator
{
get { return this.Profile; }
set
{
this.Profile = value;
}
}
public Profile Guest
{
get { return this.Profile1; }
set
{
this.Profile1 = value;
}
}
}
to avoid using Profile1 and Profile. It works but I can't use these new properties in a where clause because they are not mapped (well that's my guess).
Example:
myQuery.Where(x => x.Creator.User.UserName == userName)
I have the following exception
The specified type member 'Creator' is not supported in LINQ to
Entities. Only initializers, entity members, and entity navigation
properties are supported.
I tried to map the property like this but without any success
[Column("creator_id", TypeName="int")]
public Profile Creator
{
get { return this.Profile; }
set
{
this.Profile = value;
}
}
Is it possible?
i think you are looking for something like this
[ForeignKey("creator_id")]
public virtual Profile Creator { get; set; }
These things you commonly use for a code first approach. If you have an existing database you can reverse engineer your code first. check out http://msdn.microsoft.com/en-us/data/jj200620.aspx for an example. That way you can use the fluent API toolkit and an existing database. the best of two worlds.
I am working on an application where my database schema does not match up well to my domain model, and modifications to the database schema are not under my control. Because of this, I end up doing a lot of mapping in my repository calls, and I have many concrete repos to handle the mapping to and from the database (using entity framework database-first). What I am looking for is an elegant way to make calls to my repositories based on the domain entity object type. Thus far, the domain model itself is still very anemic, as we are still in the process of defining business rules.
I have seen an example elsewhere (can't recall the link) where the repository calls were passed through the domain entities via a static property, but I do not know if this will present threading issues or whether it violates any domain model principles, especially if we decide to implement DI/IoC down the road.
Here is an example of what I have so far. For the sake of brevity, I have simplified the mapping calls to the database, as the mapping in the actual application is more complex.
Repository example:
public interface IRepository<T>
{
T GetById(int id);
void Save(T entity);
}
public abstract class RepositoryFactory<T> : IRepository<T>
{
protected MyDbContext db;
protected int userId;
protected RepositoryFactory()
{
this.db = new MyDbContext();
this.userId = WebSecurity.GetCurrentUser().UserId;
}
public abstract T GetById(int id);
public abstract void Save(T entity);
}
public class CustomerRepository : RepositoryFactory<Customer>
{
public override void Save(Customer customer)
{
var entity = db.customers.FirstOrDefault(p => p.customerid == customer.Id && p.users.userid == userId);
if (entity == null) return; // TODO: Add error trapping
// Mapping (lots of reshaping happening here)
entity.customername = customer.Name;
entity.customeraddress = customer.Address;
// ...
// Save changes to DB
db.Entry(entity).State = EntityState.Modified;
db.SaveChanges();
}
public override Customer GetById(int id)
{
var entity = db.customers.FirstOrDefault(p => p.customerid == id && p.users.userid == userId);
if (entity == null) return null; // TODO: Add error trapping
return new Customer
{
Name = entity.customername,
Address = entity.customeraddress,
// ...
};
}
}
Domain Entity example:
public class Entity { public int Id { get; set; } }
public class Customer : Entity
{
public string Name { get; set; }
public string Address { get; set; }
// Does this violate any domain principles?
public static IRepository<Customer> Repository
{
get { return new CustomerRepository(); }
}
}
With this code, from my controller I can do something like:
Customer customer = Customer.Repository.GetById(id);
Instead of:
IRepository<Customer> repo = new CustomerRepository();
Customer customer = repo.GetById(id);
This seems like a very elegant solution to my problem, and it also keeps me from needing to include the Repository namespace in my controllers (MVC). If this smells funny and there is a better way to handle this, I'd love to learn. The only other thing I can think of is creating a separate crud service to handle my repository calls, but I imagine for that I would need a dictionary or hash table to map my concrete repos to my domain model objects, and that seems like it would be a maintenance nightmare.
I'd suggest using an inversion of control (dependency injection) container and injecting your repositories into your controllers or wherever. This way you can use them like this:
public class HomeController : Controller
{
private readonly IRepository<Customer> _customerRepository;
public HomeController(IRepository<Customer> customerRepository)
{
_customerRepository = customerRepository;
}
public ActionResult Index(int id)
{
var customer = _customerRepository.GetById(id)
return View(customer);
}
}
This way, if you ever need to replace CustomerRepository class, or need to have multiple versions (say CustomerRepositoryEntityFramework or CustomerRepositoryNHibernate) you can simply replace a new class inheriting from IRepository and your controller code will still continue to work with no change.
I recommend using Castle Windsor, or Ninject, or one of the many other IoC containers.
Also, you generally want to keep your domain entities as poco's (Plain Old CLR Object). This means separating everything out of your entities including validation, business rules, etc. and simply having only its properties. This allows you to pass your domain entities through the pipeline more easily, specially since you are in the early stages of development. This will offer you the most flexibility in the future.
Let just say I have the following data models:
public class Account
{
public string Username { get; set; }
public string Password { get; set; }
}
public class Configuration
{
public string Key { get; set; }
public string Value { get; set; }
}
For now, each of them has their own repository for data access, and uses entity framework as its unit of work/DbContext. I'm planning to pull out the Configuration part out of the entity frame and use Redis or Memcached as its data access. I might even to switch the EF to NHibernate or no ORM at all, and I might switch the database to MongoDB or CouchDB.
What is the good way to do this? To be ignorant of all those lower layer stuff in my business logic? What kind of pattern to use? Is it possible or is it just bad things to design for changes like this?
Thanks :)
As stated in the previous post, you should go the "way of the Interface".
I personally do not implement directly the repository for each orm but I use a little variation.
Using your example...
public interface IAccountRepository
{
Account Get(int id);
void Delete(int id);
...other method...
}
then you create your repository
public class AccountRepository : IAccountRepository
{
private readonly IUnitofWork unitofWork;
public AccountRepository(IUnitofWork unitofWork)
{
this.unitofWork = unitofWork;
}
//Implement interface method
public Account Get(int id)
{
//some logic or just the call to the unit of work
return unitofWork.Get(id);
}
}
I am happy with this solution because I end up with only one repository that 90% of the time use linq to query so I don't have to write the sql for each unit of work and every time I have to write a "GetAllProducts" with paging I do not have to write the same code (and tests) for every unit of work, but only for my repository. This is a simple example obviously so I hope you get the idea.
You can make a RepositoryBase that implement a method Find() or Query() which use linq.
Then with your Castle Windsor or ninject or whatever you can inject the unit of work you prefer. Hope it helps.
Update:
a sample of my UnitofWorkBase that implement nhibernate is something similar:
public class NHUnitofWork<T> : IUnitofWork<T> where T : EntityBase
{
protected INHSessionBuilder SessionBuilder { get; private set; }
public NHPersistorBase(INHSessionBuilder sessionBuilder)
{
SessionBuilder = sessionBuilder;
}
public T Get(int id)
{
T result = null;
ISession session = SessionBuilder.GetSession();
using (ITransaction transaction = session.BeginTransaction(System.Data.IsolationLevel.ReadCommitted))
{
try
{
result = (T)session.Get(typeof(T), id);
transaction.Commit();
}
finally
{
if (transaction.IsActive)
transaction.Rollback();
}
}
return result;
}
public IQueryable<T> Find()
{
return SessionBuilder.GetSession().Query<T>();
}
}
Use an interface.
public class IAccountRespository
{
public Account LoadAccountByUsername(String Username);
public void DeleteAccont(Account a);
public void SaveAccont(Account a);
.
.
.
...more methods
}
then you implement this interface on every data access object (ef,mongdb, etc. etc).
In your business logic code you use just the interface and not the acual object.
i use the factory pattern to create the data access objects, but you can use every IoC pattern.