简体   繁体   中英

Entity Framework, Repository Pattern

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

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. :)

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM