Reputation: 10624
I'm trying to use Entity Framework - Repository Pattern. (Asp.net C#, EF4)
I make repositories for each DB tables. but when I join tables, an error occur that say
"The specified LINQ expression contains references to queries that are associated with different contexts."
To avoid the error message,I put all into one class,like this :
public class WebOrderRepository
{
private DbEntities context = new DbEntities(); //Web.config <add name="DBEntities" connectionString=" ...
public IQueryable<WEBORDERHD> WebOrderHds
{
get { return context.WEBORDERHDs; }
}
public IQueryable<WEBORDERLN> WebOrderLns
{
get { return context.WEBORDERLNs; }
}
}
Could you review my code please?
This is my repository class,
public class Repository : IDisposable
{
protected ShkAdsEntities context;
private bool _disposed;
public Repository()
{
context = new ShkAdsEntities();
}
public void Dispose() //If define this class as Static then, 'Dispose': cannot declare instance members in a static class
{
DisposeObject(true);
GC.SuppressFinalize(this);
}
~Repository()
{
DisposeObject(false);
}
private void DisposeObject(bool disposing)
{
if (_disposed)
{
return;
}
if(disposing){
if (context != null)
{
context.Dispose();
}
_disposed = true;
}
}
}
public class WebOrderHdRepository : Repository
{
public IQueryable<WEBORDERHD> WebOrderHds
{
get { return context.WEBORDERHDs; }
}
public void Create(WEBORDERHD obj)
{
}
public void Delete(WEBORDERHD ojb)
{
}
public void SubmitChanges()
{
context.SaveChanges();
}
}
public class WebOrderLnRepository : Repository
{
public IQueryable<WEBORDERLN> WebOrderLns
{
get { return context.WEBORDERLNs; }
}
public void Create(WEBORDERLN obj)
{
}
public void Delete(WEBORDERLN ojb)
{
}
public void SubmitChanges()
{
context.SaveChanges();
}
}
and this is the controller for test,
[HttpGet]
public ActionResult repositoryTest()
{
WebOrderHdRepository webOrderHdRepository = new WebOrderHdRepository();
WebOrderLnRepository webOrderLnRepository = new WebOrderLnRepository();
var result = (from x in webOrderHdRepository.WebOrderHds
join u in webOrderLnRepository.WebOrderLns on x.OrderNo equals u.OrderNo
select new {x.OrderNo}).SingleOrDefault();
return Content(result.OrderNo);
}
and I try to define context as static,
protected static ShkAdsEntities context = null;
public Repository()
{
if (context == null)
{
context = new ShkAdsEntities();
}
}
then, the other error occur,
Sequence contains more than one element
Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.
Exception Details: System.InvalidOperationException: Sequence contains more than one element
Source Error:
Line 116: {
Line 117: WebOrderHdRepository webOrderHdRepository = new WebOrderHdRepository();
Line 118: WebOrderLnRepository webOrderLnRepository = new WebOrderLnRepository(); <== ERROR POINT
Line 119:
Line 120: var result = (from x in webOrderHdRepository.WebOrderHds
I search many for Entity Framework-Repository pattern. but most of things are very complicated. so I want to make it simple as above.
Please advice me~
Thanks!
[EDIT]
I try to this,
using(WebOrderHdRepository webOrderHdRepository = new WebOrderHdRepository())
using (WebOrderLnRepository webOrderLnRepository = new WebOrderLnRepository())
{
.
.
but an error occur,
The ObjectContext instance has been disposed and can no longer be used for operations that require a connection.
Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.
Exception Details: System.ObjectDisposedException: The ObjectContext instance has been disposed and can no longer be used for operations that require a connection.
Source Error:
Line 114: {
Line 115: using(WebOrderHdRepository webOrderHdRepository = new WebOrderHdRepository())
Line 116: using (WebOrderLnRepository webOrderLnRepository = new WebOrderLnRepository())
Line 117: {
Line 118:
I think it try to dispose twice time, but I don't know how to fix the code...
anybody know, please advice me~
Thanks
Upvotes: 3
Views: 5114
Reputation: 48314
An impoementation where each repository creates its own context is just wrong. Instead, the context must be injected to the repository, constructor injection works great here.
This way you have a full control of the context and of sharing it between repositories. For example, in a web app, you could have a context with a lifetime of a single request.
Upvotes: 1
Reputation: 19881
You will be able to trace the exception back to this statement:
var result = (from x in webOrderHdRepository.WebOrderHds
join u in webOrderLnRepository.WebOrderLns on x.OrderNo equals u.OrderNo
select new {x.OrderNo}).SingleOrDefault();
The fault occurs in SingleOrDefault
- your collection has more than one result. Review the MSDN documentation to determine if you should use FirstOrDefault
instead.
Specifically concerning SingleOrDefault
behavior, MSDN explains (emphasis added):
Returns the only element of a sequence, or a default value if the sequence is empty; this method throws an exception if there is more than one element in the sequence.
Regarding your DbContext, you should be able to have separate repositories, just ensure that each repository is using the same context object. I would guess (without seeing the original implementation) that each repository instantiated it's own context object. I don't see any particular issues with your current implementation although some may suggest something like the following (untested):
public ActionResult repositoryTest() {
ActionResult actionRes = default(ActionResult);
using (ShkAdsEntities context = new ShkAdsEntities())
using (WebOrderHdRepository webOrderHdRepository = new WebOrderHdRepository(context))
using (WebOrderLnRepository webOrderLnRepository = new WebOrderLnRepository(context)) {
var result = (from x in webOrderHdRepository.WebOrderHds
join u in webOrderLnRepository.WebOrderLns on x.OrderNo equals u.OrderNo
select new { x.OrderNo }).SingleOrDefault();
actionRes = Content(result.OrderNo);
}
return actionRes;
}
Update:
If you do try the repository test I demonstrate above, you will need to do some refactoring. It will not work with the current state of your classes. This would be a different question you would need to post. The above snippet is only an example of what your query could look like. Dependency Injection (DI), as @ Florim Maxhuni suggests, is really the route to go ...simply depends on your requirements and time constraints. If you have issues with your DbContext, that would be a different question and should be posted in a new thread. :)
Upvotes: 3