我是ASP.NET Core / C#的新手,并且正在努力学习。我已经阅读过教程,观看视频,甚至还买了一本书。我想把我的AppDBcontext
注入我的模特..
这是我的Startup
班级
public void ConfigureServices(IServiceCollection services)
{
// Add framework services.
string dbConnection = Configuration["ConnectionStrings:AzureSQL"];
services.AddDbContext<AppDbContext>(options => {
options.UseSqlServer(dbConnection);
});
services.AddScoped<AppDbContext>();
services.AddMvc();
}
和我的AppDbContext.cs
public class AppDbContext : DbContext
{
public AppDbContext(DbContextOptions<AppDbContext> options)
: base(options) { }
public DbSet<Monthly> Monthly { get; set; }
public DbSet<Bill> Bill { get; set; }
}
我尝试过类似我的模特
public class Bill
{
public AppDbContext _ctx;
public Bill(AppDbContext db)
{
_ctx = db;
}
public class BillGetParams
{
public string MonthlyID { get; set; }
public string UserID { get; set; }
public string BillID { get; set; }
}
public int ID { get; set; }
public int? MonthlyID { get; set; }
public string BillName { get; set; }
public string Comment { get; set; }
public int? Amount { get; set; }
public bool? Payed { get; set; }
public bool? Recursive { get; set; }
public string UserID { get; set; }
public string UUID { get; set; }
public DateTime? CreatedAt { get; set; }
public static async Task<List<Bill>> LoadBills(BillGetParams billParams)
{
var bills = _ctx.Bill.FromSql($@"
SELECT * FROM bills WHERE MonthlyId={billParams.MonthlyID}");
return await bills.ToListAsync();
}
public static async Task<Bill> LoadBill(BillGetParams param)
{
var bill = _ctx.Bill.FromSql($@"
SELECT * FROM bills
WHERE UserID='{param.UserID}' AND ID='{param.BillID}'
");
return await bill.SingleOrDefaultAsync();
}
编辑:为Bill
类和使用_ctx
的方法添加了部分代码,还通过删除static
和private-&gt; public来更新构造函数;
我收到错误:
System.NullReferenceException:未将对象引用设置为对象的实例。
因为db
到_ctx
的分配似乎从未发生过......
我不确定哪个最好,但我之前使用的是AppDbContext
。我应该继续这样使用吗?
using(var ctx = new AppDbContext())
{
var bills = ctx.Bill.FromSql($@"select 1 from bills")
// do stuff
}
从互联网上的例子来看,DI在控制器上运行良好..但我不想从控制器那里做SQL的东西..有没有更好的方法在dotnet
中抽象SQL /数据访问?或者我做错了?
解决方案1:所以,阅读,试用,@Bharat的解决方案和实验。我用最简单的方式解决了我的问题..希望我是对的。我在使用BillController
的{{1}}中添加了这个,我现在可以很好地访问我的SQL。
Bill.LoadBill()
谢谢!
答案 0 :(得分:1)
您获得{
// See http://go.microsoft.com/fwlink/?LinkId=759670
// for the documentation about the jsconfig.json format
"compilerOptions": {
"target": "es2017"
},
"exclude": [
"node_modules",
"bower_components",
"jspm_packages",
"tmp",
"temp"
]
}
的原因是因为您的构造函数方法是System.NullReferenceException: Object reference not set to an instance of an object.
:
private
解决方案:您的构造函数应为private Bill(AppDbContext db)
{
_ctx = db;
}
。
否则它不能在它自己的课程之外访问。您可以通过在public
上放置断点来测试这一点,您将看到它没有被调用。
为了进一步阅读和理解,我建议您阅读此Microsoft文档:Dependency Injection in ASP.NET Core
答案 1 :(得分:1)
我看到的最大错误就是这个:
@Configuration
@EnableTransactionManagement
@EnableJpaRepositories(
entityManagerFactoryRef = "secondaryEntityManagerFactory",
transactionManagerRef = "secondaryTransactionManager",
basePackages = {"com.ubl.*"})
public class SecondaryDBConfig {
@Autowired
JpaVendorAdapter jpaVendorAdapter;
@Value("${datasource.secondary.url}")
private String databaseURL;
@Value("${datasource.secondary.username}")
private String username;
@Value("${datasource.secondary.password}")
private String password;
@Value("${datasource.secondary.driverClassName}")
private String driverClassName;
@Value("${datasource.secondary.dialect}")
private String dialect;
public SecondaryDBConfig() {
System.out.println("Secondary repository");
System.out.println("driverClassName: *************" +driverClassName);
}
public DataSource dataSource() {
DriverManagerDataSource dataSource = new DriverManagerDataSource(databaseURL, username, password);
dataSource.setDriverClassName(driverClassName);
return dataSource;
}
@Bean(name = "secondaryEntityManager")
public EntityManager entityManager() {
return entityManagerFactory().createEntityManager();
}
@Bean(name = "secondaryEntityManagerFactory")
public EntityManagerFactory entityManagerFactory() {
Properties properties = new Properties();
properties.setProperty("hibernate.dialect", dialect);
LocalContainerEntityManagerFactoryBean emf = new LocalContainerEntityManagerFactoryBean();
emf.setDataSource(dataSource());
emf.setJpaVendorAdapter(jpaVendorAdapter);
emf.setPackagesToScan("com.ubl.model.*"); // package for entities
emf.setPersistenceUnitName("secondaryPersistenceUnit");
emf.setJpaProperties(properties);
emf.afterPropertiesSet();
return emf.getObject();
}
@Bean(name = "secondaryTransactionManager")
public PlatformTransactionManager transactionManager() {
return new JpaTransactionManager(entityManagerFactory());
}
}
我认为提供模型的方法可以直接访问它们的实例,但请不要这样做,即使是要填充额外的属性或列表。
这样您就可以在整个应用程序中拆分DataAccess代码(sql)。 相反,最好将所有dataAcces分组到控制器中,甚至更好地在单独的项目和服务中进行分组。
服务的优点是:
这将导致以下代码:
public class Bill
{
public AppDbContext _ctx;
public Bill(AppDbContext db)
{
_ctx = db;
}
public static async Task<List<Bill>> LoadBills(BillGetParams billParams)
{
var bill = _ctx... //trying to acces an instance property in static context, does not work. and shouldn't even compile.
}
}