【问题标题】:Trouble connecting to my database with entity framework c# web api无法使用实体框架 c# web api 连接到我的数据库
【发布时间】:2017-06-30 13:51:15
【问题描述】:

我有一个 LogContext 模型:

using System.Data.Entity;

namespace Logging.Models
{
    public class LogContext : DbContext
    {
        // You can add custom code to this file. Changes will not be overwritten.
        // 
        // If you want Entity Framework to drop and regenerate your database
        // automatically whenever you change your model schema, add the following
        // code to the Application_Start method in your Global.asax file.
        // Note: this will destroy and re-create your database with every model change.
        // 
        // System.Data.Entity.Database.SetInitializer(new System.Data.Entity.DropCreateDatabaseIfModelChanges<Logging.Models.ProductContext>());

        public LogContext() : base("name=LogContext")
        {
            Database.SetInitializer<LogContext>(null);
        }

        public DbSet<Log> Logs { get; set; }




    }
}

但是当我尝试在 App_code 下的其他 LogContext 类中引用日志时,我在尝试引用 context.Logs.Load(); 时遇到错误。 “不能用实例引用访问;用类型名限定它”

如何引用和呈现表中的所有行?我究竟做错了什么? 谢谢

using System;
using System.Collections.Generic;
using System.Linq;
using Logging.Controllers;
using Logging.Models;

namespace Logging
{
    public class LogContext : IDisposable
    {
        private static readonly List<Log> Logs = new List<Log>();

        static LogContext()
        {
            using (var context = new LogContext())
            {
                **context.Logs.Load();**
            }
            //Logs.Add(new Log() { Id = 1, LoggerName = "TESTSYS1", InnerException = "InnerException", LogText = "LogText", ThreadID = 1, StackTrace = "Stack Trace", eLevel = "INFO" });
            //Logs.Add(new Log() { Id = 2, LoggerName = "TESTSYS2", InnerException = "InnerException", LogText = "LogText", ThreadID = 2, StackTrace = "Stack Trace", eLevel = "ERROR" });
            //Logs.Add(new Log() { Id = 3, LoggerName = "TESTSYS3", InnerException = "InnerException", LogText = "LogText", ThreadID = 3, StackTrace = "Stack Trace", eLevel = "WARN" });
        }
        void IDisposable.Dispose()
        {

        }


        public void GetLoggies()
        {
            using (var context = new LogContext())
            {
                foreach (var log in context.GetLogs())
                {
                    Logs.Add(log);

                }
            }
        }

        public Log GetLog(int id)
        {
            var log = Logs.Find(p => p.Id == id);
            return log;
        }

        public IEnumerable<Log> GetLogs()
        {
            return LogContext.Logs;
        }

        public Log AddLog(Log p)
        {
            Logs.Add(p);
            return p;
        }

        public void Delete(int id)
        {
            var product = Logs.FirstOrDefault(p => p.Id == id);
            if (product != null)
            {
                Logs.Remove(product);
            }
        }

        public bool Update(int id, Log log)
        {
            Log rLog = Logs.FirstOrDefault(p => p.Id == id);
            if (rLog != null)
            {
                rLog = log;
                return true;
            }
            return false;
        }
    }
}

【问题讨论】:

    标签: c# asp.net-mvc-4 asp.net-web-api


    【解决方案1】:

    坦率地说,问题在于非常糟糕的设计。

    1. 您的类在此处与您的上下文具有相同的名称,并且还有一个与您的上下文中的成员同名的成员,即Logs。这是一个关于编译器有多智能的案例​​研究,因为整个事情没有爆炸的唯一原因是因为它能够在给定上下文的情况下从你想要的地方做出某种意义。不过,它可能猜错了,在某些时候肯定会感到困惑。如果您坚持以这种方式维护它,您应该完全限定您的实际上下文类的所有用途,即new Namespace.To.LogContext(),这样编译器就不会只是猜测。

    2. 在上下文中使用using 是一个非常的坏主意。理想情况下,上下文实例应该是请求范围的。除其他外,上下文使用了更改跟踪,当您开始在不同的上下文实例之间传递实体时,您将一头扎进砖墙。相反,您应该将上下文注入此类并将其保存为类中的字段。

    3. 实施IDisposable 不是您应该轻易做的事情。有一种非常特殊的方式需要实施,否则实际上弊大于利。

      public class Base: IDisposable
      {
          private bool disposed = false;
      
          //Implement IDisposable.
          public void Dispose()
          {
              Dispose(true);
              GC.SuppressFinalize(this);
          }
      
          protected virtual void Dispose(bool disposing)
          {
              if (!disposed)
              {
                  if (disposing)
                  {
                      // Free other state (managed objects).
                  }
                  // Free your own state (unmanaged objects).
                  // Set large fields to null.
                  disposed = true;
              }
          }
      
          // Use C# destructor syntax for finalization code.
          ~Base()
          {
              // Simply call Dispose(false).
              Dispose (false);
          }
      }
      

      见:https://msdn.microsoft.com/en-us/library/b1yfkh5e(v=vs.100).aspx

      然而,如果你注入你的上下文,这个类将不再拥有上下文,因此甚至不需要实现IDisposable。而且,出于对一切美好事物的热爱,在注入依赖项时不要实现IDisposable。我看到太多的开发人员这样做了,并且由于资源分配不正确而导致出现奇怪的错误。

    4. 最后,完全抛弃这个类。您实际上(错误地)在这里尝试创建的是一个存储库,您不需要它。实体框架已经实现了存储库和工作单元模式。正如您在此处的方法中所见,您所做的基本上是从您的方法代理到DbSet 上几乎等效的方法。您给自己买的只是一个现在必须维护的附加层、更多的应用程序代码熵和技术债务。有关为什么这是错误方法的更详细说明,请参阅:https://softwareengineering.stackexchange.com/a/220126/65618

    【讨论】:

    • 好的,我扔掉了 App_code 下的 LogContext 类,我从控制器重新生成了方法,现在我在 Models 下只有一个 LogContext 类,其方法如下所示: internal Log GetLog(int id ) { 抛出新的 NotImplementedException(); }
    • 我如何“注入”我的上下文?
    • 认真的吗?你知道我实际上也有一份有报酬的工作,对吧?仅仅因为我没有立即回复并没有理由失控,老实说,并不会产生真正帮助您解决该死事情的太多愿望。但是,即使如此倾向于,您也没有提供任何新的“问题”。进行这些更改后,您是否遇到相同的问题,不同的问题,究竟是什么?就注入上下文而言,选择您选择的任何 DI 容器并熟悉文档。我个人喜欢 Ninject,但还有很多其他的。
    • 那是因为它实际上很复杂。不要指望在 5 分钟内破解并在您以前从未做过的情况下找到可行的解决方案。花时间阅读文档。也许在 Pluralsight 上查看一两个视频。每月支付 29 美元,然后开始挖掘。你需要先学会走路,然后才能跑步。一次拿一块,然后继续工作,直到你到达那里。只是不要期望它快速简单,因为它不会也永远不会。
    • 基本上。要得到你可以使用Where过滤,SingleFirstFind等来获取单个项目。要创建,您实际上只是 Add 集合中的一个项目,而要删除,您实际上只是 Remove 集合中的一个项目,就像任何其他列表样式实例一样。
    猜你喜欢
    • 2012-09-17
    • 1970-01-01
    • 1970-01-01
    • 2015-07-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-04-14
    相关资源
    最近更新 更多