Attach additional ObjectSets to ObjectContext from separate project - asp.net

I hope this makes sense. I have a ASP.NET web application that uses Entity Framework. I have added a couple of custom tables to the db and created a separate project to handle the CRUD operations for those tables. I chose the separate project because I don't want future upgrades to the application to overwrite my custom features.
My problem is this. How do I attach/combine my custom ObjectContext to the ObjectContext of the application? I want to use the same UnitOfWorkScope (already in the application) to maintain the one ObjectContext instance per HTTP request. Again, I don't want to add my ObjectSets to the application's ObjectContext for my reason listed above.
Here is some code:
Widget.cs
public partial class Widget
{
public Widget()
{
}
public int WidgetId {get;set;}
public string WidgetName {get;set;}
}
WidgetObjectContext.cs
public partial class WidgetObjectContext : ObjectContext
{
private readonly Dictionary<Type, object> _entitySets;
public ObjectSet<T> EntitySet<T>()
where T : BaseEntity
{
var t = typeof(T);
object match;
if(!_entitySets.TryGetValue(t, out match))
{
match = CreateObjectSet<T>();
_entitySets.Add(t, match);
}
return (ObjectSet<T>)match;
}
public ObjectSet<Widget> Widgets
{
get
{
if((_widgets == null))
{
_widgets = CreateObjectSet<Widget>();
}
return _widget;
}
}
private ObjectSet<Widget> _widgets;
In my WidgetManager class if I was using the application's ObjectContext I would query my tables like this:
var context = ObjectContextHelper.CurrentObjectContext;
var query = from c in context.ObjectSet .... etc
What I want would be to do something like this:
var context = ObjectContextHelper.CurrentObjectContext.Attach(WidgetObjectContext);
I know this won't work but that is the gist of what I am trying to accomplish. Hope this is clear enough. Thanks.

I don't think it is possible. ObjectContext creates entity connection which connects to metadata describing mapping and database. But you have to different sets of metadata - one for ASP.NET application and one for separate project. Simply you need two connection to work with these models => you need two ObjectContexts.

FYI: The previous answer was correct at the time of the answer. It is now possible to do this using the DbContext available in EF 4.1. The caveat is that you must use the code-first strategy in order to build your custom context. In other words, you won't be able to use EDMX files to accomplish this.

Related

Best practice for managing life time of business layer, data layer, datacontext instance asp.net website

Our Asp.net web application is using LINQ-to-SQL (Stored Procs are dragged on dropped on dbml file to create classes) and 3 tier architecture is similar to the one below. I have just created rough methods to give reader proper idea so that he can answer well.
namespace MyDataLayer
{
public class MyDataAccess
{
// global instance of datacontext
MyDataModelDataContext myDB = new MyDataModelDataContext(); (#1)
public void GetUserIDByUsername(string sUserName, ref int iUserID)
{
int? iUserIDout = 0;
// this will make call to SP in SQL DB
myDB.USP_RP_GETUSERIDBYUSERNAME(sUserName, "", ref iUserIDout);
iUserID = (int)iUserIDout;
}
public List<USP_APP_USERDETAILSResult> GetUserDetails(string sUserIDs)
{
// this will make call to SP in SQL DB
return myDB.USP_APP_USERDETAILS(sUserIDs).ToList();
}
...
... // several CRUD methods
}
}
namespace MyBusinessLayer
{
public class SiteUser
{
// global DataAccess instance
MyDataLayer.MyDataAccess myDA = new MyDataAccess(); (#2)
public void GetUserIDByUsername(string sUserName, ref int iUserID)
{
myDA.GetUserIDByUsername(sUserName, ref iUserID);
}
public List<USP_APP_USERDETAILSResult> GetUserDetails(string sUserIDs)
{
// this will make call to SP in SQL DB
return myDA.GetUserDetails(sUserIDs);
}
...
... // several CRUD methods
}
}
namespace MyWebApplication
{
public class BaseWebPage : System.Web.UI.Page
{
// static business layer instance
public static MyBusinessLayer.SiteUser UserBLInstance = new SiteUser(); (#3)
...
}
}
// Index.aspx.cs code fragment
namespace MyWebApplication
{
public class Index : BaseWebPage
{
public void PopulateUserDropDown()
{
// using static business layer instance declared in BaseWebPage
List<USP_APP_USERDETAILSResult> listUsers = UserBLInstance.GetUserDetails("1,2,3");
// do databinding and so on ...
}
...
}
}
Questions
(Ref.#1) Is having global datacontext in DataAccess good approach? yes/no why?
If your suggestion is having datacontext per request what is the best practice for that
(Ref.#2) Is having global DataAccess instance in BusinessLayer good approach? yes/no why?
If your suggestion is having DataAccess instance per request what is the best practice for that
(Ref. #3) Is static business layer instance declared in BaseWebPage good approach? yes/no why?
Best approach to manage life time of BL instance and DL instance in general
We are facing periodic InvalidCastException on production server for a very simple method which works fine if I restart my application from IIS. When this problem is there we can access the same database from SQL Management Studio and can execute same SP
Our prime suspect about this issue is poor DataContext management and I have read many articles on net about managing life time of DataContext but I am now confused about various approach.
That's why I have elaborated my questions so that many in same situation can get clear idea about problem/answer.
(Ref.#1) Is having global datacontext in DataAccess good approach? yes/no why?
Yes.
However, creating it manually inside the dataaccess class means that you can't control the lifetime of the datacontext. Instead, make it then a constructor parameter so that it is injected into the data access
(Ref.#2) Is having global DataAccess instance in BusinessLayer good approach? yes/no why?
Yes. But refer to 1. - make it injectable via the constructor.
(Ref. #3) Is static business layer instance declared in BaseWebPage good approach? yes/no why?
No. Avoid static for complex objects as usually such objects has non-trivial state. And this is when a lot of nasty issues can happen if you share such objects in a concurrent environment.
To summarize.
public class DataAccess {
public DataAccess( DataContext context ) { ... }
}
public class BusinessLayer {
public BusinessLayer( DataAccess access ) { ... }
}
public class MyPage : Page {
...
var ctx = TheDataContext.Current;
var bl = new BusinessLayer( new DataAccess( ctx ) );
}
with data context shared in a request scope:
public partial class TheDataContext {
// Allow the datacontext to be shared in a request-scope
public static TheDataContext Current {
get {
if ( HttpContext.Current.Items["context"] == null )
HttpContext.Current.Items.Add( "context", new TheDataContext() );
return (TheDataContext)HttpContext.Current.Items["context"];
}
}
}
In your sample - your MyDataLayer usually has name Repository. Definitely it is good to have DataContext instance in Repositories and do not try to use them outside. So, only in repositories you will have dependency on Linq-To-Sql, which means that you can create Stub objects for these Repositories and really easy test other parts of your application.
Definitely you should Dispose your Data Context instances, DataContext contains too many objects to keep them alive and let GC to kill them. As you can see you don't create any transaction objects when you are working with DataContextes, so I think that LinqToSql based on idea that you should have everything per transaction (of course you can also try to handle transaction manually, but do you really want to do this?). Disposing datacontextes in methods of Repository is a good approach, because this will not allow you to use cool feature of all ORM frameworks: Lazy Load. If you will try to use Lazy Load - you will like it, but usually it is just one of possible performance degradation cause.
Definitely your should use DataContextes for shorter or the same time of Request, don't try to use LongSession (it is when you trying to keep DataContext for more than one Http Request, it is just pain in ass, nothing else, if you want to read about this, just try to read couple articles about Long Running Session in Hibernate, I tried with nHibernate - don't do this at home ;) ).

ASP.NET MVC to Existing ASP.NET App with BusinessLayer.Better way to load ViewModel objects from Existing BusinessLayer?

I have a legacy asp.net web application which has 2 layers , UI and BusinessLayer. The UI project is of type ASP.NET website and BL is of type class library. The BL project has classes for entities of my app like Customer,User,Empoloyee etc.. Each class has methods for Reading from Database and Populate the object properties from the DataReader.that means the Customer Class contains my Customer object and Data Access Methods together.
Now I changed the web app to support MVC too. The old site (webforms) works as it used to be and the new upgrade to the site i am making (adding admin features to manage the site) is in ASP.NET MVC3. The routing and everything works fine. But i am worried about the structure /maintainability of the project.
For the new MVC part, I had to create ViewModels for few of the Entities like CustomerViewModel,EmployeeViewModel. I created another class called "CustomerService" With methods like GetCustomerViewModel and inside that method i call the GetCustomerMethod from the Existing BusinessLayer and read property values from the object ( of entity type mentioned in the existing BL project) and assign that to the CustomerViewModel (I will look into some AutoMapper samples for this later)object and return that from this method. My View will use this object to show data in the UI. The reason i created the "CustomerService" class is i may need to do some if condition checking or some business validations before setting the values to CustomerViewModel object. I consider that as a "Middle Layer / Service layer" so that my Controllers will be thin.
From my Customer Controller
public ActionResult Details(int id)
{
MyProject.MVCViewModel.CustomerViewModel objCustomerVM;
objCustomerVM=MyProject.MVCMiddleLayer.CustomerService.GetCustomerViewModel(id);
return View(objCustomerVM);
}
In my CustomerViewModel
public static CustomerViewModel GetCustomerViewModel(int customerId)
{
//Create an object of new ViewModel
CustomerViewModel objCustomerViewModel = new CustomerViewModel ();
//Get an object from Existing BL of Customer of type ExistingBL.Customer
ExistingBL.Customer objCustOld=new Customer(customerId);
//Check some properties of the customer object and set values to the new ViewModel object
if(objCustOld.Type=="normal")
{
objCustomerViewModel.Priority=2;
}
else if(objCustOld.Type=="abnormal")
{
objCustomerViewModel.Priority=1;
objCustomerViewModel.Message ="We love you";
}
//Some other checking like this....
return objCustomerViewModel;
}
Is this a wrong approach ? Is my code going to be messy ? I am not happy about the ViewModel since it is (almost) the duplicate code from my Existing BL entities. What is the best way to address this scenario. I am not sure about using Repository Pattern (which i saw in most of the examples) in this case ? Should i do that ?How is it going to improve my code ?
The approach that I would take would be similar to repository pattern. I would outline few key points
Since the only thing that you would be rewriting would be UI logic (View Model Object), and its fine as your UI technologies are different(asp.net vs MVC)
I would suggest you start working on interfaces so that later on you could do a dependency injection. The biggest benefit I generally with dependecy injection in mvc is while writing NUnit test cases.
public static ICustomerViewModel GetCustomerViewModel(int customerId)
{
//use DI, rather than concerete implementation
ICustomerViewModel objCustomerViewModel = new CustomerViewModel ();
//use DI, rather than concerete implementation
ExistingBL.ICustomer objCustOld=new Customer(customerId);
.
.
.
return objCustomerViewModel;
}
You could now very easily create mock objects with the help of any mocking frame work.
More or less my ViewModel classes are a redefinition of properties with only attributes, someone may argue that this is just another overhead layer, but I do this for a simple reason: I can add proper Web Validation's attributes without breaking anything (The DataLayer shoudl be shareable with other apps).
In shorts given a DataLayer class exposing a User object:
public class DalUser {
public int Id { get; set;}
public int Age { get; set;}
public string Name { get; set;}
public string Surname { get; set;}
// Business method for reading/writing/deleting
}
My viewmodel is something like:
public class VmUser : DalUser
{
[Display(Name="ID Code")]
public override int Id { get; set; }
[Display(Name="Age")]
[Required]
public override int Age { get; set; }
}
This leads me to two goals: the former is I can use Attributes without worrying about breaking something else, the latter is I can hide from user some field, prevent field injection (e.g. from FireBug - but that's includes defining an Interface and using that, not plain subclassing).
That's proves pretty usefull within my corporate (we're doomed to use EntitySpaces) and it's one of the less ugly way I've found in order to partially reuse ES generated classes.

ASP.NET Site, EF, Layered Architecture, is my design ok or should I correct it?

I have a DAL project, with an entity data model context bound with EF 4.1
I provide methods to access this context through a "Business" project.
My question is the following:
I'm thinking I shouldn't reference the DAL project from somewhere other than the Business project, so my thinking is, I could add "DataContract" interfaces to the Common project I already have, reference this project within the DAL project, extend the partial classes EF has autogenerated for me, inherit the DataContracts corresponding to each of them, and use these DataContracts as the return value of operations in the Business project, thus isolating the DAL project and avoiding to tightly couple it to either the business, or web projects
Is my thinking correct or am I way off?
Update In re-reading my own question I find this kind of hard to follow, here's an example of how I'd do it, with one of the entities in the model:
The entity is:
namespace Application.Website.Main.Common.DataContracts
{
public interface IServerApplication
{
string Id { get; set; }
string ApplicationName { get; set; }
byte MaxAccountsPerUser { get; set; }
bool Enabled { get; set; }
}
}
This would be in the Application.Website.Main.Common project.
In the DAL project, I would reference the Common project, and extend the partial class of the ServerApplication to inherit from that interface, no further changes required.
namespace Application.Website.Main.DAL
{
public partial class ServerApplication : IServerApplication
{
}
}
In the Business project, I would reference both the DAL and the Common projects, and I'd use these DataContracts as return types:
namespace Application.Website.Main.Business.Entities
{
public class ServerApplication
{
public static IEnumerable<IServerApplication> Enabled()
{
var context = HttpContext.Current.GetDataContext();
return context.ServerApplications.Where(a => a.Enabled);
}
}
}
For completeness, this is the GetDataContext() extension method, placed in the DAL project:
public static class HttpContextExtensions
{
internal const string _contextDataKey = "dataContext";
public static EntityDataModelContext GetDataContext(this HttpContext httpContext)
{
if (httpContext.Items[_contextDataKey] == null)
httpContext.Items.Add(_contextDataKey, new EntityDataModelContext());
return (EntityDataModelContext)httpContext.Items[_contextDataKey];
}
}
By the way, where should I be doing the try/catching?
Should that be done on each of the Business-level methods that use the data context?
Or somewhere else?
What would be the best way to handle exceptions at this level?
Update I found a hole in my logic. If I wanted for instance to have a method in the Business class for a given entity, it would either have to be static and/or an extension method to the interface. Like this:
namespace Application.Website.Main.Business.Entities
{
public class MembershipUser
{
public static int GetRequestCount(this IMembershipUser user)
{
var context = HttpContext.Current.GetDataContext();
return context.ServerAccountRequests.Count(r => r.MembershipUserId == user.UserId);
}
}
}
Or, alternatively, just passing the least information I require for the query:
namespace Application.Website.Main.Business.Entities
{
public class MembershipUser
{
public static int GetRequestCount(Guid userId)
{
var context = HttpContext.Current.GetDataContext();
return context.ServerAccountRequests.Count(r => r.MembershipUserId == userId);
}
}
}
But how could I make a class so I can just use instance methods, like user.GetRequestCount()? Then the DataContract would need to be a class and not an interface... Or maybe I should have this class to also inherit from the DataContract, but then I would have to implement all of it's members, which I don't intend to do again, since that's already handled by EF at DAL level
I'm thinking I shouldn't reference the DAL project from somewhere
other than the Business project...
Depends how you reference it. The short answer is even you Business Logic (BL) shouldn't reference the DAL's physical implementation, it should reference an interface that defines the DAL; the concrete impelentation should then be loaded dynamically.
This is on the assumption that the project is beyond trivial in size - you can still write small PoC's, etc, anyway you like.
I could add "DataContract" interfaces to the Common project I already
have
I'd define the data contracts in their own assembly and not in a common project, otherwise everything that references the common "knows" about the data contracts (is that really what you want), and if you have any dependencies in the data contract then everything that references the common will get those extra unwanted dependencies as well.
Although I defining the data contracts should be it a separate assembly, the DTO/POCO objects could be in the common; I've done that before and had good results, because I use these objects to throw data between different layers - not just between the DAL and BL.
Your amin should be to keep all data access & EF references (like SQL) in the concrete DAL implementation.

How to pass unit of work container into constructor of repository using dependency injection

I'm trying to work out how to complete my implementation of the Repository pattern in an ASP.NET web application.
At the moment, I have a repository interface per domain class defining methods for e.g. loading and saving instances of that class.
Each repository interface is implemented by a class which does the NHibernate stuff. Castle Windsor sorts out the DI of the class into the interface according to web.config. An example of an implemented class is provided below:
public class StoredWillRepository : IStoredWillRepository
{
public StoredWill Load(int id)
{
StoredWill storedWill;
using (ISession session = NHibernateSessionFactory.OpenSession())
{
storedWill = session.Load<StoredWill>(id);
NHibernateUtil.Initialize(storedWill);
}
return storedWill;
}
public void Save(StoredWill storedWill)
{
using (ISession session = NHibernateSessionFactory.OpenSession())
{
using (ITransaction transaction = session.BeginTransaction())
{
session.SaveOrUpdate(storedWill);
transaction.Commit();
}
}
}
}
As pointed out in a previous thread, the repository class needs to accept an unit of work container (i.e. ISession) rather than instantiating it in every method.
I anticipate that the unit of work container will be created by each aspx page when needed (for example, in a property).
How do I then specify that this unit of work container instance is to be passed into the constructor of StoredWillRepository when Windsor is creating it for me?
Or is this pattern completely wrong?
Thanks again for your advice.
David
I have a persistence framework built on top of NHibernate that is used in a few Web apps. It hides the NH implementation behind an IRepository and IRepository<T> interface, with the concrete instances provided by Unity (thus I could in theory swap out NHibernate for, say, Entity Framework fairly easily).
Since Unity doesn't (or at least the version I'm using doesn't) support the passing in of constructor parameters other than those that are dependency injections themselves, passing in an extant NH ISession isn't possible; but I do want all objects in the UOW to share the same ISession.
I solve this by having a controlling repository class that manages access to the ISession on a per-thread basis:
public static ISession Session
{
get
{
lock (_lockObject)
{
// if a cached session exists, we'll use it
if (PersistenceFrameworkContext.Current.Items.ContainsKey(SESSION_KEY))
{
return (ISession)PersistenceFrameworkContext.Current.Items[NHibernateRepository.SESSION_KEY];
}
else
{
// must create a new session - note we're not caching the new session here... that's the job of
// BeginUnitOfWork().
return _factory.OpenSession(new NHibernateInterceptor());
}
}
}
}
In this example, PersistenceFrameworkContext.Current.Items accesses an IList<object> that is stored either ThreadStatic if not in a Web context, or within HttpContext.Current.Items if it is in a Web context (to avoid thread-pool problems). The first call to the property instantiates the ISession from the stored factory instance, subsequent calls just retrieve it from storage. The locking will slow things down slightly but not as much as just locking an appdomain-scoped static ISession instance.
I then have BeginUnitOfWork and EndUnitOfWork methods to take care of the UOW - I have specifically disallowed nested UOWs because frankly they were a pain to manage.
public void BeginUnitOfWork()
{
lock (_lockObject)
{
if (PersistenceFrameworkContext.Current.Items.ContainsKey(SESSION_KEY))
EndUnitOfWork();
ISession session = Session;
PersistenceFrameworkContext.Current.Items.Add(SESSION_KEY, session);
}
}
public void EndUnitOfWork()
{
lock (_lockObject)
{
if (PersistenceFrameworkContext.Current.Items.ContainsKey(SESSION_KEY))
{
ISession session = (ISession)PersistenceFrameworkContext.Current.Items[SESSION_KEY];
PersistenceFrameworkContext.Current.Items.Remove(SESSION_KEY);
session.Flush();
session.Dispose();
}
}
}
Finally, a pair of methods provide access to the domain-type-specific repositories:
public IRepository<T> For<T>()
where T : PersistentObject<T>
{
return Container.Resolve<IRepository<T>>();
}
public TRepository For<T, TRepository>()
where T : PersistentObject<T>
where TRepository : IRepository<T>
{
return Container.Resolve<TRepository>();
}
(Here, PersistentObject<T> is a base class providing ID and Equals support.)
Access to a given repository is thus in the pattern
NHibernateRepository.For<MyDomainType>().Save();
This is then facaded over such that you can use
MyDomainType.Repository.Save();
Where a given type has a specialised repository (ie needs more than it can get from IRepository<T>) then I create an interface deriving from IRepository<T>, an extending implementation inheriting from my IRepository<T> implementation, and in the domain type itself I override the static Repository property using new
new public static IUserRepository Repository
{
get
{
return MyApplication.Repository.For<User, IUserRepository>();
}
}
(MyApplication [which is called something less noddy in the real product] is a facade class which takes care of supplying the Repository instance via Unity so you have no dependency on the specific NHibernate repository implementation within your domain classes.)
This gives me full pluggability via Unity for the repository implementation, easy access to the repository in code without jumping through hoops, and transparent, per-thread ISession management.
There's lots more code than just what's above (and I've simplified the example code a great deal), but you get the general idea.
MyApplication.Repository.BeginUnitOfWork();
User user = User.Repository.FindByEmail("wibble#wobble.com");
user.FirstName = "Joe"; // change something
user.LastName = "Bloggs";
// you *can* call User.Repository.Save(user), but you don't need to, because...
MyApplication.Repository.EndUnitOfWork();
// ...causes session flush which saves the changes automatically
In my Web app, I have session-per-request, so BeginUnitOfWork and EndUnitOfWork get called in BeginRequest and EndRequest respectively.
I have a pretty similar structure to yours, and here's how I solve your question:
1) To specify my container on each method, I have a separate class ("SessionManager") which I then invoke via a static property. By doing so, here's an example using my Save implementation:
private static ISession NHibernateSession
{
get { return SessionManager.Instance.GetSession(); }
}
public T Save(T entity)
{
using (var transaction = NHibernateSession.BeginTransaction())
{
ValidateEntityValues(entity);
NHibernateSession.Save(entity);
transaction.Commit();
}
return entity;
}
2) My container is not created on each ASPX page. I instantiate all of my NHibernate goodness on the global.asax page.
** A few more things spring up **
3) You don't need to have a helper to instantiate the Load. You might as well use Get instead of Load. More information # Difference between Load and Get.
4) Using your current code, you would have to repeat pretty much the same code for each domain object you need (StoredWillRepository, PersonRepository, CategoryRepository, etc..?), which seems like a drag. You could very well use a generic class to operate over NHibernate, like:
public class Dao<T> : IDao<T>
{
public T SaveOrUpdate(T entity)
{
using (var transaction = NHibernateSession.BeginTransaction())
{
NHibernateSession.SaveOrUpdate(entity);
transaction.Commit();
}
return entity;
}
}
In my implementation, I could then use something like:
Service<StoredWill>.Instance.SaveOrUpdate(will);
Technically, the answer to my question is to use the overload of container.Resolve which allows you to specify the constructor argument as an anonymous type:
IUnitOfWork unitOfWork = [Code to get unit of work];
_storedWillRepository = container.Resolve<IStoredWillRepository>(new { unitOfWork = unitOfWork });
But let's face it, the answers provided by everyone else have been much more informative.

ASP.NET MVC design

As I've stated before I'm working on a digg clone to teach myself ASP.NET MVC Inside and out but I've hit a road bump that I can't seem to avoid.
I want to be able to optimize this application as much as possible so I have my DAL which is a bunch of classes of ...Repository : Repository. Now to help optimize for performance I have my base repository classes return my ViewData objects so that they can select extra fields needed without having to create an anonymous type.
Stories have Users who have created them and Users have Votes for Stories. Pretty easy DB layout. Now I handle my own membership because the default ASP.NET membership is so bloated. In my view for the list of stories I have to determine if the current user has voted on the story being rendered. Now since I figured data access in the View shouldn't be happening it should be in either my controller or my DAL. Since I'm already returning ViewData from my DAL i added another property on the StoryViewData type named "UserVotedOn" that returns true if the user has voted on that story.
Problem with this is I have to either A) make the DAL aware of membership or B) pass in the User ID into the query methods on the DAL. Neither of these feel right to me and I'm looking for some good solutions. Any feedback is welcome.
In my MVC apps I'm using architecture that Rob Conery showed on his MVC Storefront video series and it works like charm for me.
Repository => Service + Filters => Controller => View
I've tried to simulate what you want to achieve and managed todo like this
Edit1: Changed IList to IQueryable in repository and filters
Repository
public interface IRepository
{
IQueryable<Vote> GetVotes();
IQueryable<Story> GetStories();
}
Service for getting what you want
public class Service : IService
{
private IRepository _repository;
public Service(IRepository repository)
{
_repository = repository;
if (_repository == null) throw new InvalidOperationException("Repository cannot be null");
}
public IList<Vote> GetUserVotes(int userID)
{
return _repository.GetVotes().WithUserID(userID).ToList();
}
public IList<Story> GetNotVotedStories(IList<Vote> votes)
{
return _repository.GetStories().WithoutVotes(votes).ToList();
}
}
Filters to filter your stories and user votes (These are basically extension methods). Not the nicest implementation out there, but you can rewrite later
public static class Filters
{
public static IQueryable<Vote> WithUserID(this IQueryable <Vote> qry, int userID)
{
return from c in qry
where c.UserID == userID
select c;
}
public static IQueryable<Story> WithoutVotes(this IQueryable <Story> qry, IList <Vote> votes)
{
return from c in qry
where votes.Where(x => x.StoryID == c.StoryID).ToList().Count > 0
select c;
}
}
And then you can pass current UserID in controller, not in DAL or View like you had to do before
public class HomeController : Controller
{
private readonly IRepository _repository;
private readonly IService _service;
public HomeController()
{
_repository = new Repository();
_service = new Service.Service(_repository);
}
public ActionResult Index()
{
var userVotes = _service.GetUserVotes(CurrentUserID);
var unvotedStories = _service.GetNotVotedStories(userVotes);
return View(unvotedStories);
}
}
This allows you to stay away from adding user related UserVotedOn property to your Story model
It looks like you're missing the BLL.
Actually, the right architecture of an MVC application is what many people still trying to figure out.
I personally consider UserID to be somewhat a translayer concept. It will appear on both DAL and BLL levels.
Basically, your controller method should have just a few very basic calls to the BLL, only to determine how to react to user input, whether to return on view or another.
Your view should only deal with model objects. A model should probably be filled by the business logic. You could call BL methods in a controller method in order to initialize you model object and then pass it to the view.
Controller should not communicate directly with the database. Neither should it probably deal with low level objects which comprise your domain objects and models.
P.S. i would try to avoid extensive use of ViewData. Strongly-typed model classes are a much better option. You can also group them in hierarchies to inherit some common properties. Just like your domain model classes could derive from a base class that has a UserID property defined.

Resources