Entity Framework 4 - Generic method for retrieving entity by ID - entity-framework-4

I am writing method for fetching single entities by their ID :
public Customer GetCustomer(int i_CustomerID)
{
return (from c in context.CustomerSet
where c.Id == i_CustomerID
select c).SingleOrDefault();
}
public Movie GetMovie(int i_MovieID)
{
return (from m in context.MovieSet
where m.Id == i_MovieID
select m).SingleOrDefault();
}
But I have many entities and this code repeats itself. I want to write a method like this:
public T GetEntityByID<T>(int i_EntityID)
{
return (from e in context.T_Set
where e.Id == i_EntityID
select e).SingleOrDefault();
}
Is there a way to achieve that ?

I haven't actually executed this but it compiles and is probably something along the lines of what you are trying to achieve:
public static void Testing()
{
SelectEntity<MyObject>(r => r.MyObjectId == 1);
}
public static T SelectEntity<T>(Expression<Func<T, bool>> expression) where T : EntityObject
{
MyContext db = new MyContext();
return db.CreateObjectSet<T>().SingleOrDefault(expression);
}

The problem is that there is no common super type that has the relevant properties that you seek. It is easy, however, to code generate your fetch methods using the in-built T4 code generation tool that EF is using. Here is a good link on how to hook in and generate the sort of code you need.
http://msdn.microsoft.com/en-us/data/gg558520

If you know that your generic repository will be always used with entity types which have PK with the same name and the same type you can simply define interface like this:
public interface IEntity
{
int Id { get; }
}
and either implement this interface in partial part of your generated entities or modify T4 template to include it automatically. Your repository will be then defined as:
public interface IRepository<TEntity> where T : IEntity
{
...
}
If the type of PK can change but the name is still the same you can improve the entity interface to:
public interface IEntity<TKey>
{
TKey Id { get; set; }
}
and the definition of repository will be:
public interface IRepository<TEntity, TKey> where TEntity : IEntity<TKey>
{
...
}
If you want generic repository which is able to work with entities with different PK's name and type check this answer. That solution should probably also work (or with small modification) with composite PKs.

Related

Generic save method

In my generic repository I need to write generic Save method which will edit existed or add new entity depending on id.
public void Save<T>(T entity) where T : TEntity, IKeyId
{
if (ObjectSet.Any(r => (r as IKeyId).KeyId == entity.KeyId))
{
Edit(entity);
}
else
{
Add(entity);
}
}
But Linq generate exception when I try do Any( r=> (r as IKeyId)....
The 'TypeAs' expression with an input of type 'MyProg.DAL.Appeal' and a check of type 'Claimstrak.DAL.Interfaces.IKeyId' is not supported. Only entity types and complex types are supported in LINQ to Entities queries.
How to write it correct?
Well, the truth is that you dont need to use the ObjectSet, you can just use DbContext to do this, in a much more easy way.
Bu, i would tell that this is not a good pattern to use, to call a Save() in a repository. I would recomend that you consider the .SaveSession() of the Context only after all was done, this way you can do a lot of things befose making a round trip to te database.
So, you should make a method like this, but not call the SaveChanges(), instead of a Save() method, to a UpdateOrInsert() and them, after all is done you call the .Save()
But i will give the examplefollowing your request (but i dont recommend, i recommend you separate IUnitOfWork from IRepository)
See how the code is very simple:
interface IKeyId
{
int Id { get; set; }
}
DbContext context = new YourContext();
public bool Save<TEntity>(TEntity entity) where TEntity : class, IKeyId
{
return (entity.Id == 0) ? Add<TEntity>(entity) : Edit<TEntity>(entity);
}
public bool Edit<TEntity>(TEntity entity) where TEntity : class, IKeyId
{
var set = context.Set<TEntity>();
set.Attach(entity);
return true;
}
public bool Add<TEntity>(TEntity entity) where TEntity : class, IKeyId
{
var set = context.Set<TEntity>();
set.Add(entity);
return true;
}
I use a similar approach im my repositories, i have changed the T4 (.tt file) that generates the POCO classes from my database to excplicitly implement some interfaces that i have, such as IAuditable, IValidatable and other, so the T4 automaticaly implement those interfaces in the classes.

Entity framework add a where clause to all queries

I am using Entity framework 5 and using repository pattern. Say I got these entities Customer, Files, Images, Tasks, Invoice, User.
Each entity (apart from Customer) has a foreign key of Customer. When a user logs in I store the customerid in session (aps.net mvc). What I want is any CRUD taken on all entities to be limited to the customer who's user is logged in. e.g I can't afford to delete a Task belonging to customer 1 to be deleted by user who is from customer 2.
Is adding an argument of customerid for each method of repositories the best way to achieve this or are there any better/clever ways of doing it?
Tricky to give a definitive answer but you could make it a bit more extensible by implementing higer order functions, like this:
public interface IRepository<T>
{
public T GetBy(Expression<Func<T, bool>> query)
}
public class FileRepository : IRepository<File>
{
public File GetBy(Expression<Func<T, bool>> query)
{
using(var context = new FilesContext())
{
return context.Files.Where(query).FirstOrDefault();
}
}
}
public class SomeController
{
private IRepository<File> _repo;
public SomeController(IRepository<File> repo)
{
_repo = repo;
}
public ActionResult Index()
{
var model = _repo.GetBy(f => f.CustomerId == Session.Whatever.CustomerId);
return View(model);
}
}
This way you can vary the search query when required, rather than tie yourself in to using a hardcoded customer id property. For example, if you wanted to get the File object by the FileID, not the CustomerID, then:
var model = _repo.GetBy(f => f.FileId == someId);
and that's the only part of the code that needs to change.
Some really good info on Higher Order functions and functional programming in C# here: http://www.codeproject.com/Articles/375166/Functional-programming-in-Csharp
Edit:
You might be able to isolate the "Always use the customer ID when hitting DB" into a repository of it's own, using a decorator style pattern, thus: (massive disclaimer - I haven't tested this, but something along these lines should work)
public class SpecialFileRepo : IRepository<File>
{
private readonly IRepository<File> _baseRepo;
public SpecialFileRepo(IRepository<File> baseRepo)
{
_baseRepo = baseRepo;
}
public SpecialFileRepo() : this(new FileRepository())
{
}
public File GetBy(Expression<Func<File, bool>> query)
{
var parameters = query.Parameters;
var newParam = Expression.Parameter(typeof (File), "f");
var additionalQuery = Expression.AndAlso(query.Body,
Expression.Equal(
Expression.PropertyOrField(newParam, "CustomerId"),
Expression.Constant(HttpContext.Current.Session["customerId"])));
var newQuery = query.Update(additionalQuery, parameters);
return _baseRepo.GetBy(newQuery);
}
}
Then anything that's talking to a repository, as far as it's concerned, it's just a base repository, but this class is sitting in between and always grafting the "customerid = sessionwhatever" expression onto what finally gets passed to the database. And of course, anything that only cares about using the base repository, can still do so.

Does using Implicit / Explicit conversion operators violate Single Responsibility Pattern in favor of DRY?

I need to convert between these two classes, and want to maintain DRY but not violate the Single Responsibility Pattern...
public class Person
{
public string Name {get;set;}
public int ID {get;set;}
}
public class PersonEntity : TableServiceEntity
{
public string Name {get;set;}
public int ID {get;set;}
// Code to set PartitionKey
// Code to set RowKey
}
More Info
I have some Model objects in my ASP.NET MVC application. Since I'm working with Azure storage I see the need to convert to and from the ViewModel object and the AzureTableEntity quite often.
I've normally done this left-hand-right-hand assignment of variables in my controller.
Q1
Aside from implicit/explicit conversion, should this code be in the controller(x) or the datacontext(y)?
Person <--> View <--> Controller.ConverPersonHere(x?) <--> StorageContext.ConvertPersonHere(y?) <--> AzurePersonTableEntity
Q2
Should I do an implicit or explicit conversion?
Q3
What object should contain the conversion code?
Update
I'm also implementing WCF in this project and am not sure how this will affect your recommendation . Please also see this question.
Q1: The controller.
Q2: Convert manually or with the help of a mapping tool such as AutoMapper.
Q3: I would put the code for this in a converter or mapper class like the following. Note that IConverter is shared among all converters, and IPersonConverter just exists so your controllers and service locators can use it.
public interface IConverter<TModel, TViewModel>
{
TViewModel MapToView(TModel source);
}
public interface IPersonConverter : IConverter<PersonEntity, Person>
{
}
public class PersonConverter : IPersonConverter
{
#region IPersonConverter
public Person MapToView(PersonEntity source)
{
return new Person
{
ID = source.ID,
Name = source.Name
};
//or use an AutoMapper implementation
}
#endregion
}

Are related records loaded into HashSet or SortedSet?

Assume we have POCO class for Entity Framework 4:
public class Order
{
public long Id { get; set; }
public ISet<OrderItem> OrderItems { get; set; }
}
And this method to retrieve the order from database:
public Order GetOrder(long orderId)
{
using (var context = new MyModelEntities())
{
return context.Orders.Include("OrderItems").Where(order => order.Id == orderId).FirstOrDefault();
}
}
So suppose we do this:
Order myOrder = GetOrder(1);
Is myOrder.OrderItems a HashSet or SortedSet? Is there a way to control this?
Good question.
As far as i know (and there is no MSDN/blog/article i am aware of that dispells/proves this), a navigational property can be of any type as long as it implements ICollection<T>.
Both HashSet<T> and SortedSet<T> implement ICollection<T>, so either would be viable candidates.
Did you step through the code? You should be able to see which concrete class get's resolved.
Most people use ICollection<T> / IList<T>. Why are you wanting to declare the property as ISet<T>?
Why don't you just declare which type you want, instead of the interface.
Or you could try using dependency injection (For<ISet>().Use<HashSet>()).

NHibernate - Sorting Entities based on Property/Column + how to manage?

I'm writting an ASP.NET MVC e-commerce app using NHibernate and I want the end-user to be able to control the ordering of Product Categories (not just have them appear alphebetically etc.).
Normally, I'd add an OrderIndex/Sort column (of type int) to the Category table, and property to the Category domain class. But the problem is in having to constantly manage this special OrderIndex/Sort column as Categories are sorted, added, and deleted. I'd rather hide it away and make it transparent so callers don't have to set the property directly.
Sure I could write my own code to manage all this, but wanted to know if NHibernate has anything built in that could help me, or if it could hook this property up automatically.
If not then I was thinking of creating an OrderedEntity base class (all domain objects derive from an Entity base), and create an IOrderedRepository base Repository as well. Something like this:
public class Entity
{
public virtual int Id { get; set; }
}
public class OrderedEntity : Entity
{
public virtual int OrderIndex { get; set; }
}
public class Category : OrderedEntity
{
}
public interface IRepository<T> where T : Entity
{
T FromId(int id);
void Save(T entity);
}
public interface IOrderedRepository<T> : IRepository<T> where T : OrderedEntity
{
void MoveUp(int places);
void MoveDown(int places);
}
Does this seem like a good approach? I don't want to reinvent an inferior wheel.
So far I know Hibernate has an annotation #OrderBy where you can specify the ordering when the collection is loaded. But Hibernate won't manage the position that for you when you add or remove element in the collection.
You can however easily do that yourself and provide methods addItem and removeItem on the parent entity, which will keep track of the position (or the methods MoveUp and MoveDown as you suggest).

Resources