lte实体网络框架_用网络核心实体框架解决现实生活中的场景

lte实体网络框架

Today we will talk about real-life requests, problems, errors. And we will find a solution all of them by one by, by using .Net Core Entity Framework. “Current .Net Core version 3.1.401”.

今天,我们将讨论现实生活中的要求,问题和错误。 并且,我们将使用.Net Core Entity Framework逐一找到所有解决方案。 “ 当前的.Net Core版本3.1.401”。

“We can not solve our problems with the same level of thinking that created them.”

“我们无法用产生问题的相同水平来解决问题。”

— Albert Einstein

- 艾尔伯特爱因斯坦

1-)将某些属性保存到数据库时,我需要对其进行加密。 从数据库读取数据时,我需要对其解密。 (1-) I need to encrypt some properties when saved them to DB. And I need to decrypt them when I read it from DB.)

Firstly we must solve this problem globally and manage it from one place.We will create CryptoData Attribute for signing the secret fields.

首先,我们必须全局解决此问题并从一个地方进行管理。我们将创建CryptoData属性以对秘密字段进行签名。

CryptoData.cs: This attribute is used for flagged to secret properties of the class.

CryptoData.cs:此属性用于标记该类的秘密属性。

using System;
using System.Collections.Generic;
using System.Text;namespace Dashboard.DB.PartialEntites
{
[AttributeUsage(AttributeTargets.All)]
public class CryptoData : System.Attribute
{
public CryptoData()
{
}
public int id { get; set; }
}
}

In this scenario, we will encrypt, User’s Gsm numbers.

在这种情况下,我们将加密用户的Gsm号码。

DbUser.cs: This is User entity class.

DbUser.cs :这是用户实体类。

using System;
using System.Collections.Generic;namespace Dashboard.DB.Entities
{
public partial class DbUser
{
public int IdUser { get; set; }
public string Name { get; set; }
public string LastName { get; set; }
public string UserName { get; set; }
public string Password { get; set; }
public string PasswordHash { get; set; }
public string Email { get; set; }
public string Gsm { get; set; }
public bool IsDeleted { get; set; }
public bool? IsAdmin { get; set; }
}
}

If you are using Database First, you have to create a MetaData class for signing the property of any DbSet<T> class on DBContext. Because if you put directly [CryptoData] attribute to Gsm property on the existing DbSet class, you could lose your custom changing codes on DataContext. If someone called the scaffolding, all the classes would be generated from the DB again, and all your custom codes are gone.

如果使用数据库优先,则必须创建一个MetaData 用于在DBContext上签名任何DbSet <T>类的属性。 因为如果直接将[CryptoData]属性放到现有DbSet类的Gsm属性上,则可能会丢失DataContext上的自定义更改代码。 如果有人调用了脚手架,则将再次从数据库中生成所有类,并且所有自定义代码都消失了。

UserMetaData.cs: This is our UserMetaData class. We signed Gsm property with this class.

UserMetaData.cs :这是我们的UserMetaData类。 我们为此课程签署了Gsm属性。

public class UserMetaData
{
[CryptoData(id = 5)]
public string Gsm { get; set; }
}

We attached this UserMetaData to the DbUser class, so we signed the Gsm property as a secret field.

我们将此UserMetaData附加到DbUser类,因此我们将Gsm属性签名为秘密字段。

[MetadataType(typeof(UserMetaData))]
public partial class DbUser : BaseEntity

This is the example of the Insert method on Repository. We will check all properties of the Inserted entity. And we will look for the marked with “CryptoData” property. If we find it, we will save it as encrypted.

这是存储库上Insert方法的示例。 我们将检查插入实体的所有属性。 我们将寻找标记为“ CryptoData ”的属性。 如果找到它,则将其保存为加密文件。

Repository/Insert():

仓库/ Insert():

public void Insert(T entity)
{
if (entity == null)
throw new ArgumentNullException(nameof(entity));
using (var dbContext = _provider.GetVbtContext(connection))
{
DbSet<T> _entities = dbContext.Set<T>();
entity = EncryptEntityFields(entity, _context);
entity.UsedTime = DateTime.Now;
_entities.Add(entity);
dbContext.SaveChanges();
}
}

EncryptEntityFields(): Firstly we will check, there is any “MetadataTypeAttribute” in the class. If there is, we will check all property info in Metadata. If we found the” CryptoData” attribute, we will encrypt the selected property’s value.

EncryptEntityFields() :首先,我们将检查类中是否有任何“ MetadataTypeAttribute”。 如果存在,我们将检查元数据中的所有属性信息。 如果找到“ CryptoData ”属性,则将加密所选属性的值。

After all, if you want to encrypt any property of any entities, only adding [CryptoData] attributes on it is enough. You don’t have to write any more code.

毕竟,如果要加密任何实体的任何属性,仅在其上添加[CryptoData]属性就足够了。 您无需再编写任何代码。

public virtual T EncryptEntityFields(T entity, DashboardContext dbContext)
        {
            MetadataTypeAttribute[] metadataTypes = entity.GetType().GetCustomAttributes(true).OfType<MetadataTypeAttribute>().ToArray();
            foreach (MetadataTypeAttribute metadata in metadataTypes)
            {
                System.Reflection.PropertyInfo[] properties = metadata.MetadataClassType.GetProperties();              
                foreach (System.Reflection.PropertyInfo pi in properties)
                {             
                    if (Attribute.IsDefined(pi, typeof(DB.PartialEntites.CryptoData)))
                    {
                        int id = ((CryptoData)pi.GetCustomAttributes(true)[0]).id;
                        dbContext.Entry(entity).Property(pi.Name).CurrentValue = _encryption.EncryptText(dbContext.Entry(entity).Property(pi.Name).CurrentValue.ToString());
                    }
                }
            }
            return entity;
        }

Encrypt() & Decrypt() Methods: These are the, encrypt and decrypt methods.

Encrypt()和Decrypt()方法:这些是加密和解密方法。

public string DecryptText(string text, string privateKey = "")
        {
            try
            {
                if (string.IsNullOrEmpty(text) || text == "null")
                    return string.Empty;


                if (string.IsNullOrEmpty(privateKey))
                    privateKey = _vbtConfig.Value.PrivateKey;


                using (var provider = new TripleDESCryptoServiceProvider())
                {
                    provider.Key = Encoding.ASCII.GetBytes(privateKey.Substring(0, 16));
                    provider.IV = Encoding.ASCII.GetBytes(privateKey.Substring(8, 8));


                    var buffer = Convert.FromBase64String(text);
                    return DecryptTextFromMemory(buffer, provider.Key, provider.IV);
                }
            }
            catch
            {
                throw new InvalidTokenException();
            }
        }


        private string DecryptTextFromMemory(byte[] data, byte[] key, byte[] iv)
        {
            using (var ms = new MemoryStream(data))
            {
                using (var cs = new CryptoStream(ms, new TripleDESCryptoServiceProvider().CreateDecryptor(key, iv), CryptoStreamMode.Read))
                {
                    using (var sr = new StreamReader(cs, Encoding.Unicode))
                    {
                        return sr.ReadToEnd();
                    }
                }
            }
        }


        public string EncryptText(string text, string privateKey = "")
        {
            if (string.IsNullOrEmpty(text) || text == "null")
                return string.Empty;


            if (string.IsNullOrEmpty(privateKey))
                privateKey = _vbtConfig.Value.PrivateKey;


            using (var provider = new TripleDESCryptoServiceProvider())
            {
                provider.Key = Encoding.ASCII.GetBytes(privateKey.Substring(0, 16));
                provider.IV = Encoding.ASCII.GetBytes(privateKey.Substring(8, 8));


                var encryptedBinary = EncryptTextToMemory(text, provider.Key, provider.IV);
                return Convert.ToBase64String(encryptedBinary);
            }
        }


        private byte[] EncryptTextToMemory(string data, byte[] key, byte[] iv)
        {
            using (var ms = new MemoryStream())
            {
                using (var cs = new CryptoStream(ms, new TripleDESCryptoServiceProvider().CreateEncryptor(key, iv), CryptoStreamMode.Write))
                {
                    var toEncrypt = Encoding.Unicode.GetBytes(data);
                    cs.Write(toEncrypt, 0, toEncrypt.Length);
                    cs.FlushFinalBlock();
                }


                return ms.ToArray();
            }
        }

Repository/GetById(): This method is used for getting data from all entities by ID. And if there is any encrypted property in it, we will decrypt and return it.

Repository / GetById() :此方法用于通过ID从所有实体获取数据。 并且如果其中包含任何加密的属性,我们将对其解密并返回。

public virtual T GetById(object id)
{
T entity = Entities.Find(id);
return DecryptEntityFields(entity, _context);
}

“It’s very hard to keep an uncrackable encryption if you share it with the government.” — John McAfee

“如果要与政府共享,则很难保留不可破解的加密。” -约翰·迈克菲(John McAfee)

DecryptEntityFields: With this method, we will check metadataTypeAttributes, and if we find we will check all properties, and if there is “CryptoData” property info, we will decrypt this field.

DecryptEntityFields:使用此方法,我们将检查metadataTypeAttributes,如果发现,我们将检查所有属性,并且如果存在“ CryptoData ”属性信息,我们将对该字段进行解密。

public virtual T DecryptEntityFields(T entity, DashboardContext _dbcontext)
        {
            MetadataTypeAttribute[] metadataTypes = entity.GetType().GetCustomAttributes(true).OfType<MetadataTypeAttribute>().ToArray();
            foreach (MetadataTypeAttribute metadata in metadataTypes)
            {
                System.Reflection.PropertyInfo[] properties = metadata.MetadataClassType.GetProperties();
                //All the properties of the entity assigned the metadata are taken one by one.
                foreach (System.Reflection.PropertyInfo pi in properties)
                {
                    //If the related property has a CryptoData flag, the corresponding value is Decrypt.
                    if (Attribute.IsDefined(pi, typeof(DB.PartialEntites.CryptoData)))
                    {
                        //int id = ((CryptoData)pi.GetCustomAttributes(true)[0]).id;
                        _dbcontext.Entry(entity).Property(pi.Name).CurrentValue = _encryption.DecryptText(_dbcontext.Entry(entity).Property(pi.Name).CurrentValue.ToString());
                    }
                }
            }
            return entity;
        }
Image for post

2-)更新任何实体时都需要它; 我不想设置所有字段。 我不想浪费很多时间来一一设置所有属性。 (2-) I need it when I update any entity; I don’t want to set all fields. I don’t want to lose lots of time to set all properties one by one.)

UpdateMatchEntity: All records are assigned from one entity to another without going through column synchronization while updating.

UpdateMatchEntity:将所有记录从一个实体分配给另一个实体,而无需在更新时进行列同步。

_context.Entry(updateEntity).CurrentValues.SetValues(setEntity);

We will check all property’s current value, and if they are null, we will set the “IsModified” property false. So when the entity creates an Update script, these columns will not be added in the set property. And finally, if there is a CryptoData attribute on any property, it will be encrypted again.

我们将检查所有属性的当前值,如果它们为null,则将“ IsModified ”属性设置为false。 因此,当实体创建更新脚本时,这些列将不会添加到set属性中。 最后,如果任何属性上都有一个CryptoData属性,它将再次被加密。

Repository/UpdateMatchEntity:

仓库/ UpdateMatchEntity:

public virtual void UpdateMatchEntity(T updateEntity, T setEntity, bool isEncrypt = false)
{
if (setEntity == null) //Lates state of the Update Data
throw new ArgumentNullException(nameof(setEntity)); if (updateEntity == null) //Old state of the Updated Data
throw new ArgumentNullException(nameof(updateEntity)); //We will set all properties from setEntity to updateEntity
_context.Entry(updateEntity).CurrentValues.SetValues(setEntity); //We will check all propery's current value.
foreach (var property in _context.Entry(setEntity).Properties)
{
if (property.CurrentValue == null) {
_context.Entry(updateEntity).Property(property.Metadata.Name).IsModified = false; }
} updateEntity = UpdateEncryptedEntityFieldIfChange(updateEntity);
_context.SaveChanges();
}

UpdateEncryptedEntityFieldIfChange(): If the class has a Metadata attribute, all the properties of the entity are checked one by one. If one of the properties is signed with CryptoData, it’s value encrypted.If the current encrypted property is changed, the new value is encrypted and set it over the old one.

UpdateEncryptedEntityFieldIfChange():如果类具有Metadata属性,则实体的所有属性都将一一检查。 如果其中一个属性是使用CryptoData签名的,则其值将被加密;如果当前加密的属性被更改,则将对新值进行加密并将其设置为旧值。

public virtual T UpdateEncryptedEntityFieldIfChange(T entity)
        {
            MetadataTypeAttribute[] metadataTypes = entity.GetType().GetCustomAttributes(true).OfType<MetadataTypeAttribute>().ToArray();
            foreach (MetadataTypeAttribute metadata in metadataTypes)
            {
                System.Reflection.PropertyInfo[] properties = metadata.MetadataClassType.GetProperties();
                //If the class has a Metadata attribute, all the properties of the entity checked one by one.
                foreach (System.Reflection.PropertyInfo pi in properties)
                {
                    //If one of the property is signed with CryptoData, it's value encrypted.
                    if (Attribute.IsDefined(pi, typeof(DB.PartialEntites.CryptoData)))
                    {
                        //int id = ((CryptoData)pi.GetCustomAttributes(true)[0]).id;
                        //If the current encrypted property is changed, the new value is encrypted and set it over the old one.
                        if (_context.Entry(entity).Property(pi.Name).OriginalValue.ToString() != _encryption.EncryptText(_context.Entry(entity).Property(pi.Name).CurrentValue.ToString()))
                        {
                            _context.Entry(entity).Property(pi.Name).CurrentValue = _encryption.EncryptText(_context.Entry(entity).Property(pi.Name).CurrentValue.ToString());
                        }
                        else
                        {
                            //If there is no change, IsModified set false.
                            _context.Entry(entity).Property(pi.Name).IsModified = false;
                        }
                    }
                }
            }
            return entity;
        }

This is the example of the usage of the UpdateMatchEntity() method.

这是UpdateMatchEntity()方法的用法示例。

“I will always choose a lazy person to do a hard job. Because a lazy person will find an easy way to do it.”

“我总是会选择一个懒惰的人去努力。 因为一个懒惰的人会找到一种简单的方法来做到这一点。”

— Bill Gates.

- 比尔盖茨。

SecurityService/UpdateMatchEntity():

SecurityService / UpdateMatchEntity():

  • “entityViewModel” : This is a security updated model.

    “ entityViewModel”:这是安全更新的模型。
  • “_repository.GetById” : We will get the current model of the Security entity.

    “ _repository.GetById”:我们将获取安全实体的当前模型。
  • “_repository.UpdateMatchEntity(currentModel, updateModel)”: We will call UpdateMatchEntity() with a current and updated model of the Security entity. So we won’t match updated columns one by one.

    “ _repository.UpdateMatchEntity(currentModel,updateModel)”:我们将使用安全实体的当前模型和更新模型来调用UpdateMatchEntity()。 因此,我们不会一一匹配更新的列。
public IServiceResponse<SecurityControllerModel> UpdateMatchEntity(SecurityControllerModel entityViewModel, int userId)
{
var response = new ServiceResponse<SecurityControllerModel>(null); var updateModel = _mapper.Map<DB.Entities.DbSecurityController>(entityViewModel); var currentModel = _repository.GetById(updateModel.IdSecurityController);
if (currentModel != null)
{
_repository.UpdateMatchEntity(currentModel, updateModel);
var returnModel = _mapper.Map<SecurityControllerModel>(currentModel);
response.Entity = returnModel;
}
else
{
throw new NotImplementedException();
}
return response;
}

3-)我不想向所有Linq Entity查询添加“ isDelete == false”条件。 (3-) I don’t want to add “isDelete ==false” condition to all Linq Entity queries.)

DB/ISoftDeletable.cs: Firstly we will create an ISoftDeleteable interface for marking the entities, which we select not use “x => !x.Deleted” filter for the query.

DB / ISoftDeletable.cs:首先,我们将创建一个ISoftDeleteable接口来标记实体,我们选择对查询不使用“ x =>!x.Deleted”过滤器。

using System;
using System.Collections.Generic;
using System.Text;namespace Dashboard.DB.PartialEntites
{
public interface ISoftDeletable
{
bool Deleted { get; set; }
}
}

DB/PartialEntities.cs: In this example, we marked partial DbUser with the “ISoftDeletable()” interface.

DB / PartialEntities.cs:在此示例中,我们使用“ ISoftDeletable() ”接口标记了部分DbUser。

public partial class DbUser : BaseEntity, ISoftDeletable { }

DB/VbtContext.cs: “modelBuilder.AddGlobalFilter()”: When VbtContext class is rising up, OnModelCreating() method is triggered, so we can call our custom AddGlobalFilter() modelBuilder extension.

DB / VbtContext.cs: “ modelBuilder.AddGlobalFilter()”:当VbtContext类上升时,将触发OnModelCreating()方法,因此我们可以调用自定义的AddGlobalFilter()modelBuilder扩展。

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.AddGlobalFilter();
}

DB/ModelBuilderExtensin.cs: Look for all Entity types in the model and find those that are ISoftDeletable and Call the SetSoftDeleteFilter() method. On this method we will add “x => !x.Deleted” QueryFilter to Entity.

DB / ModelBuilderExtensin.cs:在模型中查找所有Entity类型,并找到可ISoftDeletable的类型,然后调用SetSoftDeleteFilter()方法。 在此方法上,我们将向实体添加“ x =>!x.Deleted ” QueryFilter。

using Dashboard.DB.PartialEntites;
using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;


namespace Dashboard.DB.Extensions
{
    public static class ModelBuilderExtensions
    {
        public static void AddGlobalFilter(this ModelBuilder modelBuilder)
        {        
            foreach (var type in modelBuilder.Model.GetEntityTypes())
            {
                if (typeof(ISoftDeletable).IsAssignableFrom(type.ClrType))
                    modelBuilder.SetSoftDeleteFilter(type.ClrType);
            }
        }


        public static void SetSoftDeleteFilter(this ModelBuilder modelBuilder, Type entityType)
        {
            SetSoftDeleteFilterMethod.MakeGenericMethod(entityType)
                .Invoke(null, new object[] { modelBuilder });
        }


        static readonly MethodInfo SetSoftDeleteFilterMethod = typeof(ModelBuilderExtensions)
                   .GetMethods(BindingFlags.Public | BindingFlags.Static)
                   .Single(t => t.IsGenericMethod && t.Name == "SetSoftDeleteFilter");


        public static void SetSoftDeleteFilter<TEntity>(this ModelBuilder modelBuilder)
            where TEntity : class, ISoftDeletable
        {
            modelBuilder.Entity<TEntity>().HasQueryFilter(x => !x.Deleted);
        }
    }
}

Finally, while writing a Linq query, we are globally filtered deleted records from the entities marked with ISoftDeletable.

最后,在编写Linq查询时,我们将从标记有ISoftDeletable的实体中全局删除记录。

Image for post

4-)因为我SQL查询结果没有模型类型,所以我想将Custom DbSet <T>类添加到DBContext。 (4-) I want to add Custom DbSet<T> class to DBContext because of no model type of my SQL query results.)

Core/Model/CustomAboneModel.cs: This is the custom result model of AboneService. There is no table like that on SQL. Therefore, we should define this model to DBContext.

Core / Model / CustomAboneModel.cs:这是AboneService的自定义结果模型。 在SQL上没有这样的表。 因此,我们应该将此模型定义为DBContext。

namespace Dashboard.DB.Entities
{
public partial class CustomAboneModel : BaseEntity
{
public decimal AboneNo { get; set; }
public string AboneTipiAdi { get; set; }
}
}

Service/Abone/GetAboneByRawSql(): This is our custom subscriber select query service. The return type is “CustomAboneModel.” This class has no equivalent in DBContext. So normally, you can not call FromSqlRaw() method from DBContext on the ”_customAboneRepository” class for this custom model type.

Service / Abone / GetAboneByRawSql():这是我们的自定义订户选择查询服务。 返回类型为“ CustomAboneModel”。 此类在DBContext中没有等效项。 因此,通常,对于这种自定义模型类型,您不能从“ _customAboneRepository”类上的DBContext中调用FromSqlRaw()方法。

private readonly IRepository<CustomAboneModel> _customAboneRepository;
public AboneService(IRepository<CustomAboneModel> customAboneRepository)
{
   _customAboneRepository = customAboneRepository; 
}


public ServiceResponse<CustomAboneModel> GetAboneByRawSql()
{
    var result = _customAboneRepository.GetSql("SELECT top 1 AboneNo, AboneTipiAdi FROM AB_ABONE Q1 INNER JOIN AB_ABONE_TIPI Q2 ON Q1.IdAboneTipi = Q2.IdAboneTipi ");
    var response = new ServiceResponse<CustomAboneModel>(null);
    response.List = result.ToList();
    return response;
}

GeneralRepository/GetSql(): This method executes the string raw SQL query with the “FromSqlRaw(sql)” entity method.

GeneralRepository / GetSql():此方法使用“ FromSqlRaw(sql) ”实体方法执行字符串原始SQL查询。

public IEnumerable<T> GetSql(string sql)
{
return Entities.FromSqlRaw(sql).AsNoTracking();
}

Description: VbtContext is our inherited of DBContext. And _entities is one of the DBSet of DBContext.

说明: VbtContext是我们继承自DBContext。 _entities是DBContext的DBSet之一。

private readonly VbtContext _context;protected virtual DbSet<T> Entities => _entities ?? (_entities = _context.Set<T>());

私有只读VbtContext _context;受保护的虚拟DbSet <T>实体=> _entities? (_entities = _context.Set <T>());

Now let’s define the CustomAboneModel to VbtContext.

现在,我们将CustomAboneModel定义为VbtContext。

VbtContext.cs: We must declare “CustomAboneModel” DbSet<>in this class.

VbtContext.cs:我们必须在此类中声明“ CustomAboneModel” DbSet <>。

  • public DbSet<CustomAboneModel> CustomAboneModel { get; set; }”: We define CustomeAboneModel as DbSet.

    public DbSet <CustomAboneModel> CustomAboneModel {get; 组; } ”:我们将CustomeAboneModel定义为DbSet。

  • modelBuilder.Entity<CustomAboneModel>(entity => { entity.HasNoKey(); })”: We have to set HasNoKey for this Entity. If you don’t use it, you get an error. “HasNoKey” Entities are never tracked for changes in the DbContext and therefore are never inserted, updated, or deleted on the database. It is only used for database queries.

    modelBuilder.Entity <CustomAboneModel>(entity => {entity.HasNoKey();}) ”:我们必须为此实体设置HasNoKey 。 如果不使用它,则会出现错误。 从未跟踪“ HasNoKey”实体在DbContext中的更改 ,因此也从未在数据库上插入,更新或删除过它们。 它仅用于数据库查询。

public class VbtContext : DashboardContext
{
public VbtContext()
{
}
public DbSet<CustomAboneModel> CustomAboneModel { get; set; } public VbtContext(DbContextOptions<DashboardContext> options)
: base(options){}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder); modelBuilder.Entity<CustomAboneModel>(entity =>
{
entity.HasNoKey();
}); modelBuilder.AddGlobalFilter();
}
}

5-)我想在运行时在控制台上看到LINQ to SQL语句SQL命令。 (5-) I would like to see the SQL command of the LINQ to SQL statements at run time on the console.)

This is really a justified request for every developer. Because all developer wants to see, their LINQ query performance, so this query script created independently from the DB and can be seen on the Output Window. Db could be SQL, Oracle, or other database technologies.

对于每个开发人员来说,这确实是一个合理的要求。 因为所有开发人员都希望看到他们的LINQ查询性能,所以此查询脚本独立于数据库创建,并且可以在“输出”窗口中看到。 Db可以是SQL,Oracle或其他数据库技术。

Image for post
Image Source: 图像来源: logging-in-efcorelogging-in-efcore

VbtContext.cs: All DB scripts can be seen only debug mode for the performance. We will use the LoggerFactory class for getting converted linq SQL queries. We will add LogLevel and Database Command Name filter for getting specific log data.

VbtContext.cs:所有DB脚本只能在调试模式下查看,以提高性能。 我们将使用LoggerFactory类获取转换后的linq SQL查询。 我们将添加LogLevel和Database Command Name过滤器以获取特定的日志数据。

protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
 {
      #if DEBUG
          base.OnConfiguring(optionsBuilder.UseLoggerFactory(VbtLoggerFactory));
      #endif
      #if RELEASE
          base.OnConfiguring(optionsBuilder);
      #endif
 }


 /* It allows us to see the generated sql script while it is in debug mode in linq queries. */
 public static readonly ILoggerFactory VbtLoggerFactory
  = LoggerFactory.Create(builder =>
  {
        builder
            .AddFilter((category, level) =>
                category == DbLoggerCategory.Database.Command.Name
                && level == LogLevel.Information)
            .AddDebug();
  });
Image for post

结论: (Conclusion:)

In this article, we try the solve real-life scenarios With .Net Core 3.1. These items are the features that software developers want from me in real business life. I shared some of them with you. I hope they will help you to save your time.

在本文中,我们尝试使用.Net Core 3.1解决实际情况。 这些项目是软件开发人员在现实生活中希望我获得的功能。 我和你分享了其中的一些。 希望他们能帮助您节省时间。

THE END & GOOD BYE
终结与再见

“If you have read so far, first of all, thank you for your patience and support. I welcome all of you to my blog for more!”

“如果您到目前为止已经阅读过,首先,感谢您的耐心和支持。 我欢迎大家 我的博客 更多!”

Source: entityframework.net, pluralsight.com, microsoft.com, entityframeworktutorial.net

来源: entityframework.netpluralsight.commicrosoft.comentityframeworktutorial.net

翻译自: https://medium.com/swlh/solving-real-life-scenarios-with-net-core-entity-framework-78c0d60faef2

lte实体网络框架

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值