我无法弄清楚为什么 TransactionScope 正在启动分布式事务(未在 SQL Server 上配置)。我想改用本地事务,当两个数据库位于同一个 SQL Server 实例中时可以使用本地事务。我的代码有什么问题,我该如何修复它?我可以强制 Transaction Scope 首先尝试本地事务吗?
数据库
应用程序设置.json
{
"ConnectionStrings": {
"DefaultConnection": "Data Source=DESKTOP;Initial Catalog=test;Integrated Security=True",
"Test2Connection": "Data Source=DESKTOP;Initial Catalog=test2;Integrated Security=True"
}
}
Run Code Online (Sandbox Code Playgroud)
startup.cs注册 TestContext 和 Test2Context
services.AddDbContext<TestContext>(options =>
options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));
services.AddDbContext<Test2Context>(options =>
options.UseSqlServer(Configuration.GetConnectionString("Test2Connection")));
services.AddTransient<ICustomerRepository, CustomerRepository>();
services.AddTransient<IMaterialRepository, MaterialRepository>();
// This service inject TestContext and Test2Context
services.AddTransient<ICustomerService, CustomerService>();
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
Run Code Online (Sandbox Code Playgroud)
使用 TestContext 的CustomerRepository
public class CustomerRepository : ICustomerRepository
{
private readonly TestContext _context;
public CustomerRepository(TestContext context)
{
_context = context;
}
public Customer Retrieve(int id) …Run Code Online (Sandbox Code Playgroud) sql-server transactionscope distributed-transactions dbcontext entity-framework-core
我想注册一个作用域ICurrentUserService,然后在 DbContext 中使用它来设置CreatedBy每个实体的属性。我希望它具有作用域,因为它使用 currentHttpContext从声明中获取用户 id,并且 HttpContext 根据定义具有作用域。
services.AddTransient<ICurrentUserService, CurrentUserService>();
Run Code Online (Sandbox Code Playgroud)
但是,当我尝试将其与 DbContextFactory 一起使用时,如下所示:
services.AddDbContextFactory<MyDbContext>(options =>
options.UseSqlServer(config.ConnectionStrings.MSSQLConnection, x =>
{
x.MigrationsHistoryTable("...");
x.MigrationsAssembly("...");
}));
services.AddScoped<IMyDbContext>(provider => provider.GetRequiredService<IDbContextFactory<MyDbContext>>().CreateDbContext());
services.AddScoped<MyDbContext>(provider => provider.GetRequiredService<IDbContextFactory<MyDbContext>>().CreateDbContext());
Run Code Online (Sandbox Code Playgroud)
我收到错误
无法从根提供程序解析作用域服务“SomeNamespace.ICurrentUserService”。
我可以将其更改为 Transient,但这似乎是错误的,并且当我想模拟它并且每个类都会获得一个新实例时,这可能会成为稍后测试的问题。
我实际上不确定为什么 Scoped 在这里不起作用。DbContextFactory 已注册为 Singleton,但 Context 也被解析为 Scoped。
dependency-injection dbcontext entity-framework-core .net-core
我使用两个数据库上下文进行读取和写入,指向相同的数据库模式。
ReadDbContext和WriteDbContext有自己的读取和写入模型。
由于这两种上下文配置中的关系、表名以及最后的数据库都是相同的,因此只有其中之一可以构建数据库。
有没有办法禁用为指定数据库上下文应用创建的迁移的能力?更进一步,是否有可能禁止迁移创建?
我尝试添加Database.SetInitializer<TContext>(null)到 DbContext 构造函数,但这似乎在 EF Core 6 中不起作用。
为了更好地理解,您可以查看下面的代码。
读取数据库上下文
internal sealed class ReadDbContext : DbContext
{
public DbSet<UserReadModel> Users => Set<UserReadModel>();
public DbSet<RoleReadModel> Roles => Set<RoleReadModel>();
public DbSet<PermissionReadModel> Permissions => Set<PermissionReadModel>();
public ReadDbContext(DbContextOptions<ReadDbContext> options) : base(options)
{
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.HasDefaultSchema("user-manager");
var configuration = new ReadConfiguration();
modelBuilder.ApplyConfiguration<UserReadModel>(configuration);
modelBuilder.ApplyConfiguration<RoleReadModel>(configuration);
modelBuilder.ApplyConfiguration<PermissionReadModel>(configuration);
}
}
Run Code Online (Sandbox Code Playgroud)
写数据库上下文
internal sealed class WriteDbContext : DbContext
{ …Run Code Online (Sandbox Code Playgroud) c# dbcontext entity-framework-core entity-framework-migrations
我正在尝试从服务调用存储库中的方法。
上下文、存储库和服务都被定义为范围服务。
这是我首先调用的方法:
public async void ReceiveWebhook(HttpContext httpContext)
{
// some unimportant checks here
var productPurchaseRequest = new ProductPurchaseRequest
{
Amount = Convert.ToInt32(result?.Quantity),
Timestamp = DateTime.Now,
ProductType = productType,
PaymentProviderOrderId = Convert.ToInt32(result?.OrderId),
PaymentProviderProductId = Convert.ToInt32(result?.ProductId),
PaymentProviderTransactionId = result?.TransactionId!,
PaymentModel = PaymentModel.Subscription,
PhoneNumber = result?.Passthrough!
//todo: change payment model
};
var bought = await _productProvisioningRepository.PurchaseProduct(productPurchaseRequest);
}
Run Code Online (Sandbox Code Playgroud)
这是方法:PurchaseProduct()在存储库中:
public async Task<bool> PurchaseProduct(ProductPurchaseRequest productPurchaseRequest)
{
await using var transactionScope = await _context.Database.BeginTransactionAsync();
var query = from u in _context.signumid_user
where u.PhoneNumber …Run Code Online (Sandbox Code Playgroud) 我在开发项目时遇到错误。
我的代码如下..
错误信息 :
System.ArgumentException:使用配置调用“AddDbContext”,但上下文类型“NoteDbContext”仅声明无参数构造函数。这意味着传递给“AddDbContext”的配置将永远不会被使用。如果配置传递给“AddDbContext”,则“NoteDbContext”应该声明一个接受 DbContextOptions 的构造函数,并且必须将其传递给 DbContext 的基本构造函数。
数据库上下文
public class NoteDbContext : DbContext
{
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
base.OnConfiguring(optionsBuilder);
optionsBuilder.UseSqlServer(
"Server=DESKTOP-BELVBNK\\SQLEXPRESS;" +
"DataBase=NoteAppDB;Trusted_Connection=True;");
}
public DbSet<Entities.Note> Notes { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
ASP.Net 项目 - 启动
public void ConfigureServices(IServiceCollection services)
{
services.AddControllersWithViews();
services.AddDbContext<NoteDbContext>(options =>
options.UseSqlServer(Configuration.GetConnectionString("NoteAppDB")));
}
Run Code Online (Sandbox Code Playgroud)
我搜索了这些错误的解决方案,但找不到。
我有类层次结构,如下所示:
class BaseType
{
[Key]
[DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
[DataType(DataType.Text)]
[StringLength(100)]
public string CreatedBy { get; set; }
[DataType(DataType.DateTime)]
public DateTime? CreatedDate { get; set; }
....
}
class Group : BaseType
{
public string Name { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
这是OnModelCreating方法的上下文:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<MCQGroup>()
.HasKey(t0 => t0.Id)
.Map(m => m.ToTable("groups"))
.HasMany(t1 => t1.Sections)
.WithMany(t2 => t2.Groups)
.Map(m =>
m.MapLeftKey("group_id")
.MapRightKey("section_id")
.ToTable("groups_to_sections"));
...........
}
Run Code Online (Sandbox Code Playgroud)
我没有使用自动表格生成或迁移.相反,我有许多脚本来创建数据库(实际上,我在第一次运行时使用自动生成,之后脚本创建的表包括webdata_*表).这是由多个上下文引起的,在这种情况下,表自动生成存在许多问题.
这是SQL脚本:
-- Tables creation
CREATE TABLE [groups] …Run Code Online (Sandbox Code Playgroud) 这类事总是让我烦恼,所以我想我会从聪明的人那里寻找一种"更好的方式".
我有一个查询,我想返回单个字段的值,这是一个int值.
int thivalue = (from q in context.tablename
where q.ID == id
orderby q.fieldname descending
select q).FirstOrDefault().fieldname;
Run Code Online (Sandbox Code Playgroud)
问题是查询可能没有返回结果,在这种情况下我希望thisvalue为0.
当然,如果没有结果,我会尝试访问不存在的字段.所以我的选择似乎是a)返回行(我不需要),所以我可以测试null并从那里开始,或者b)在它周围包装一个try catch并将值设置为0,其中看起来有点笨重.
我想也许DefaultIfEmpty()会帮助我,但似乎不是我想要的只是单个值.
那么这样做的正确方法是什么?当我只需要一个单独的值时,我只是顽固地想要不返回整行吗?
附录:(如果有人有兴趣)
在他的回答中,berkeleybross给了我两个明显相同的选择.但只有第二个给了我正确的结果.OrderByDescending似乎有些不对劲.使用Glimpse我查看了每个查询.
var nextSequence = db.PaneContents
.Where(q=>q.QuizPaneID == quizPaneId)
.OrderByDescending(q=>q.Sequence)
.Select (q=>q.Sequence)
.DefaultIfEmpty()
.First();
Run Code Online (Sandbox Code Playgroud)
产生了这个查询:
SELECT
CASE WHEN ([Limit1].[C1] IS NULL) THEN 0 ELSE [Limit1].[Sequence] END AS [C1]
FROM ( SELECT TOP (1)
[Project1].[Sequence] AS [Sequence],
[Project1].[C1] AS [C1]
FROM ( SELECT 1 AS X ) AS [SingleRowTable1]
LEFT OUTER JOIN (SELECT
[Extent1].[Sequence] AS [Sequence], …Run Code Online (Sandbox Code Playgroud) 我想知道在使用Web站点的上下文类连接到db时,性能和一般最佳实践的差异是什么.考虑这两种不同的方法时,最好的方法是什么:
public class Repository()
{
Private Context context;
public List<User> GetUsers()
{
return this.context.Users.ToList();
}
Run Code Online (Sandbox Code Playgroud)
要么
public class Repository()
{
public List<User> GetUsers()
{
using (Context context = new context())
{
return context.Users.ToList();
}
}
}
Run Code Online (Sandbox Code Playgroud)
如果它将结果作为a List或as 返回是否重要IEnumerable?
在线查看一些MVC示例,我看到通常在控制器中DbContext变量被声明为私有成员变量(即全局)并且可以被所有方法访问.
但是,我最近遇到了一篇关于ASP.NET身份的文章,并且在控制器中注意到,DbContext是在每个方法中声明的(需要它).
这种方法有安全上的好处吗?或许限制安全对象的生命周期以获得更好的整体安全性?!?!
如果没有,那么我看到第一种方法更有效,其中数据库上下文在控制器加载时被实例化.
以下是我能找到的关于DbContext的全部内容,但没有什么可以真正回答我的问题.
我在MSDN中使用了EF6中新的测试双打.VS2013与Moq和nUnit.一切都很好,直到我不得不这样做:
var myFoo = context.Foos.Find(id);
然后:
myFoo.Name = "Bar";
然后 :
context.Entry(myFoo).Property("Name").IsModified = true;
此时是我收到错误的地方:
附加信息:无法为属性"名称"调用成员"IsModified",因为上下文中不存在"Foo"类型的实体.要向上下文添加实体,请调用DbSet的Add或Attach方法.
虽然,当我用AddWatch检查上下文中的'Foos'时,我可以在运行测试之前看到我添加的所有项目.所以他们在那里.
我从文章中创建了FakeDbSet(或TestDbSet).我将每个FakeDbSet放在构造函数中的FakeContext中,每个构造函数都被初始化.像这样:
Foos = new FakeDbSet<Foo>();
我的问题是,是否可以使用测试双精度场景使用FakeDbSet和FakeContext,以便从测试双重访问DbEntityEntry和DBPropertyEntry?谢谢!
dbcontext ×10
c# ×3
.net-core ×2
.net ×1
asp.net ×1
asp.net-mvc ×1
entity-framework-migrations ×1
identity ×1
moq ×1
sql-server ×1
testing ×1