Entity Framework - 2.3
Extension ID
com.castsoftware.entity
What’s new?
See Release Notes for more information.
Description
This extension provides support for Entity Framework. The calculation of Automated Function Points for your .NET analyses will be supplemented through the links between objects produced by the base .NET Analyzer and database tables, using Entity Framework CRUD operations.
In what situation should you install this extension?
If your .NET application contains Entity Framework source code and you want to view these object types and their links, then you should install this extension. More specifically the extension will identify:
- “call” links from C# methods using Entity Framework operations to Entity framework operation objects
- “use” links from Entity framework operation objects to participating Database tables
Technology support
The following .NET framework / Libraries are supported by this extension:
Framework / Library name | Version | Supported | Supported Technology | Comments |
---|---|---|---|---|
Entity Framework (EF, EF6) | 3.0 to 6.4.x | ✅ | C# | |
Entity Framework Core (EF Core) | 1.0.x to 9.0.x | ✅ | C# | |
Z.EntityFramework.Plus.EF6 | 1.6.4 to 7.21.0 | ✅ | C# | Entity Framework Plus extends DbContext with must-have features: Include Filter, Auditing, Caching, Query Future, Batch Delete and Batch Update. |
Z.EntityFramework.Plus.EFCore | 2.22.3 to 7.22.4 | ✅ | C# | Same as above |
Z.BulkOperations | 2.12.4 to 5.2.2 | ✅ | C# | |
Z.EntityFramework.Extensions | 3.11.20 to 9.103.9 | ✅ | C# | |
Z.EntityFramework.Extensions.EFCore | 2.103.9 to 9.103.9 | ✅ | C# | |
EFCore.BulkExtensions | 1.0 to 7.1 | ✅ | C# | |
EntityFramework6.BulkInsert | 6.0.3 | ✅ | C# | |
LINQ to Entities - Method syntax | ✅ | C# | ||
LINQ to Entities - Query syntax | ✅ | C# |
Function Point, Quality and Sizing support
This extension provides the following support:
- Function Points (transactions): a green tick indicates that OMG Function Point counting and Transaction Risk Index are supported
- Quality and Sizing: a green tick indicates that CAST can measure size and that a minimum set of Quality Rules exist
Function Points (transactions) | Quality and Sizing |
---|---|
✅ | ❌ |
Compatibility
Core release | Operating System | Supported |
---|---|---|
8.4.x | Microsoft Windows / Linux | ✅ |
8.3.x | Microsoft Windows | ✅ |
Download and installation instructions
The extension will be automatically downloaded and installed in CAST Console. You can manage the extension using the Application - Extensions interface.
What results can you expect?
Objects
Icon | Object Type Description | Comment |
---|---|---|
![]() |
EF Entity | Created when the DbSet Entity is declared in the derived class inheriting from DbContext |
![]() |
EF Entity Operation | Used when CRUD operation is performed on Entity |
![]() |
EF SQL Query | Used for native queries |
![]() |
EF Unknown SQL Query | Used when the query could not be resolved |
![]() |
EF Unknown Entity | Created and used when the entity could not be resolved |
![]() |
EF Unknown Entity Operation | Used when CRUD operation is performed and Entity could not be resolved |
Links
Link type | Source and destination of link | Methods supported |
---|---|---|
callLink useInsertLink |
callLink between the caller .NET Method object and EF Entity Operation /EF Unknown Entity Operation object useInsertLink between the EF Entity Operation object and Database Table object |
Insert Operation through EF APIs
Insert Operation through EF Core DbSet & DbContext APIs
Insert Operation through ObjectContext APIs
Insert Operation through EFCore.BulkExtensions
Insert Operation through Z.BulkOperations and Z.EntityFrameworkInsert Operation through EntityFramework.BulkInsert |
callLink useDeleteLink |
callLink between the caller .NET Method object and EF Entity Operation / EF Unknown Entity Operation object useDeleteLink between the EF Entity Operation object and Database Table object |
Delete Operation through EF APIs
Delete Operation through EF Core DbSet & DbContext APIs
Delete Operation through ObjectContext APIs
Delete Operation through EFCore.BulkExtensions
Delete Operation through Z.BulkOperations and Z.EntityFramework |
callLink useUpdateLink |
callLink between the caller .NET Method object and EF Entity Operation /EF Unknown Entity Operation object useUpdateLink between the EF Entity Operation object and Database Table object |
Update Operation through EF Core DbSet & DbContext
Update Operation through EFCore.BulkExtensions
Update Operation through Z.BulkOperations and Z.EntityFramework |
callLink useSelectLink |
callLink between the caller .NET Method object and EF Entity Operation / EF Unknown Entity Operation object useSelecttLink between the EF Entity Operation object and Database Table object |
Select Operation through EF APIs
Select Operation through EF Core APIs
Select Operation through Microsft.EntityFrameworkCore.EntityFrameworkQueryableExtensions APIs
Select Operation through Z.EntityFramework.Plus APIs
Select Operations in EF Plus supported through Eval-Expression.Net Library
Select Operation through EFCore.BulkExtensions |
callLink | callLink between the caller .NET Method object and EF SQL Query / EF Unknown SQl Query object |
Execute APIs
Execute APIs supported through ObjectContext APIs |
relyOnLink |
relyOnLink between the EF Entity and .NET Class |
Code examples
Insert operation
Insert operation
Add
public static void GenerateData()
{
using EntityContext context = new();
context.Customers.Add(new Customer() { Name = "Customer_A", Description = "Description", IsActive = true });
}
Insert Operation through dbcontext.Set<T>
Insert through dbcontext.Set
public void SaveCalculatedCycles(string discriminator, IEnumerable<AuditCycle> calculatedCycles)
{
foreach (AuditCycle cycle in calculatedCycles)
{
MissionAuditCycle saveableCycle = new MissionAuditCycle
{
DateOfEarliestAuditPerformed = cycle.DateOfEarliestAuditPerformed,
StartDate = cycle.StartDate,
EndDate = cycle.EndDate,
MissionDiscriminatorWithoutIndex = discriminator,
ShiftId = cycle.ShiftId
};
_dbContext.Set<MissionAuditCycle>().Add(saveableCycle);
}
}
Insert Operation through ObjectContext
Insert Operation through ObjectContext
public void AddToACCESS_RIGHT_STATUS(ACCESS_RIGHT_STATUS aCCESS_RIGHT_STATUS)
{
base.AddObject("ACCESS_RIGHT_STATUS", aCCESS_RIGHT_STATUS);
}
BulkSynchronize (Insert, Delete, Update) through Z.BulkOperations
Insert Operation through BulkSynchronzie
public static void Main()
{
using (var context = new AppDbContext())
{
context.Database.EnsureCreated();
// Create BulkOperation instance
var bulk = new BulkOperation(context);
// BulkSynchronize (sync data: insert, update, delete)
var syncList = new List<Employee>
{
new Employee { Name = "Only One Left" }
};
bulk.BulkSynchronize(syncList);
Console.WriteLine("BulkSynchronize done via Z.BulkOperations.BulkOperation.BulkSynchronize");
}
}
Delete operation
Delete operation
Delete
public override void DeleteEntity(Entities context, object entity)
{
var entityToRemove = (ShelfInspectionCreationPermission)entity;
if (entityToRemove.AdditionApprovalId != null) { context.AdditionApprovals.Remove(entityToRemove.AdditionApproval); }
if (entityToRemove.DeletionApprovalId != null) { context.DeletionApprovals.Remove(entityToRemove.DeletionApproval); }
entityToRemove.User_Depots.ToList().ForEach(ud => ud.ShelfInspectionCreationPermission = null);
context.ShelfInspectionCreationPermissions.Remove(entityToRemove);
}
Delete Operation through ObjectContext
Delete Operation through ObjectContext
public void DeleteACCESS_RIGHT_STATUS(ACCESS_RIGHT_STATUS aCCESS_RIGHT_STATUS)
{
base.DeleteObject(aCCESS_RIGHT_STATUS);
}
Batch Delete Operation through EF Plus
Delete Operation through EF Plus
public override void DeleteEntity(Entities context, object entity)
{
var entityToRemove = (Role_SupplierComplaints_ProcessingStage)entity;
if (entityToRemove.AdditionApprovalId != null) { context.AdditionApprovals.Remove(entityToRemove.AdditionApproval); }
if (entityToRemove.DeletionApprovalId != null) { context.DeletionApprovals.Remove(entityToRemove.DeletionApproval); }
context.Role_SupplierComplaints_ProcessingStage.Remove(entityToRemove);
}
Delete Operation through BatchDeleteExtensions
Delete Operation through BatchDeleteExtensions
public static void Main()
{
using (var context = new AppDbContext())
{
context.Database.EnsureCreated();
// DeleteFromQuery
context.Empl.Where(p => p.Name.Contains("Temp"))
.DeleteFromQuery();
Console.WriteLine("DeleteFromQuery via Z.BulkOperations.Queryable.DeleteFromQuery");
}
}
Update Operation
Update operation
Update
public void UpdateContractorAddress()
{
var contractor = dbContext.Contractor.FirstOrDefault();
contractor.Address = ModelFakes.ContractorFake.Generate().Address;
dbContext.Contractor.Update(contractor);
dbContext.SaveChanges();
}
Batch Update Operation through EF Plus
Batch Update Operation through EF Plus
public static void UpdateRows()
{
EntityContext context = new ();
context.Customers.Where(x => x.Name == "Customer_C").Update(x => new Customer {Description = "Updated_C",IsActive = false});
}
Update Operation through Z.BulkOperations
Update Operation through Z.BulkOperations
public static void Main()
{
using (var context = new AppDbContext())
{
context.Database.EnsureCreated();
// Use Extensions.BulkInsert
var initial = new List<Employee>
{
new Employee { Name = "Alice" },
new Employee { Name = "Bob" }
};
// Create BulkOperation instance
var bulk = new BulkOperation(context);
// BulkUpdate
initial.ForEach(p => p.Name += " Updated");
bulk.BulkUpdate(initial);
Console.WriteLine("BulkUpdate done via Z.BulkOperations.BulkOperation.BulkUpdate");
}
}
Bulk Operations through EFCore.BulkExtensions
Bulk Operations
public static void BulkOperations()
{
List<InvoiceItem> invoiceDetails = new List<InvoiceItem>
{
new InvoiceItem { InvoiceItemId = 1, ProductName ="Apple" },
new InvoiceItem { InvoiceItemId = 2, ProductName = "Orange"},
// Add more invoice details to synchronize
};
var context = new EntityContext();
context.BulkInsertOrUpdateOrDelete(invoiceDetails);
}
Select operation
Select operation
Find
protected void AssignPermissionToUser(User user, int depotId, Entities context)
{
var user_depotEntity = context.User_Depots.Find(user.Id, depotId);
if (user_depotEntity.ShelfInspectionCreationPermission != null)
{
throw new EntityConflictException("Permission already existing or pending.");
}
}
Select operation through Z.EntityFramework.Plus
Select
public static void QueryDeferredTrial()
{
using EntityContext context = new();
//Query Cache
context.Customers.DeferredCount().FromCache();
}
LINQ-To-Entities
LINQ-To-Entities
Method Syntax
public string[] GetColumnPermissionsOfUser(int id, string tableName)
{
using (var context = new Entities())
{
List<int> userRoles = context.User_Roles
.Where(ur => ur.UserId == id)
.Where(ur => ur.AdditionApproval.ApprovedAt.HasValue)
.Where(ur => ur.Role.AdditionApproval.ApprovedAt.HasValue)
.Select(ur => ur.RoleId)
.ToList();
}
}
Query Syntax
public int GetCount()
{
var resultat1 = (from cartItems in storeDB.Carts
where cartItems.CartId == ShoppingCartId
select (int?)cartItems.Count).ToList();
}
Support for EntityModelConfiguration
EntityModelConfiguration allows configuration to be performed for any entity type in a model. Support has be been provided to create callLink between method and entity operation object and appropriate crud link between entity operation object and table, when table name is overridden through EntityModelConfiguration.
EntityModelConfiguration
public DomainModel.Portaalstatus OpslaanLogin(Account account)
{
using (new LoggingMonitoredScope(LogConstants.Diagnostics))
{
ValidationHelper.Validate(account);
if (ClaimHelper.IsMeekijker())
return new DomainModel.Portaalstatus();
var cacheKey = CacheSettingsHelper.CreateCacheKey(account);
_cacheHelper.Remove(cacheKey, CacheGroups.CacheGroupPortaalStatussen);
DomainModel.Portaalstatus cacheItem;
using (var dbContext = new ApfPortalenDbContext())
{
var portaalstatus =
dbContext.Portaalstatussen.FirstOrDefault(
p => p.AdministratieId.Equals(account.AdministratieIdentificatie) &&
p.RelatienummerDeelnemerMaia.Equals(account.RelatienummerDeelnemerMAIA));
if (portaalstatus == null)
{
portaalstatus = dbContext.Portaalstatussen.Add(new Portaalstatus());
}
};
}
Support for CRUD operations using dbContext
CRUD using dbcontext
public async Task<IActionResult> Create(Distribution distribution)
{
if (ModelState.IsValid)
{
context.Add(distribution);
await context.SaveChangesAsync();
return RedirectToAction("Index");
}
else
return View();
}
Support for ExecuteSqlQuery
ExecuteSqlCommand
protected void InsertInfo(List<DispatcherInfo> entities)
{
int chunkSize = 1000;
var pendingBar = new PendingBar(Logger);
pendingBar.Start();
Entities context = new Entities();
try
{
entities.GroupBy(e => e.DepotId).ToList().ForEach(g =>
{
context.Database.ExecuteSqlCommand("DELETE FROM DispatcherInfoes WHERE DepotId = {0}", g.Key);
context.BulkInsert(g.ToList(), chunkSize);
context.SaveChanges();
});
}
catch (Exception)
{
throw;
}
finally
{
pendingBar.Stop();
if (context != null)
context.Dispose();
}
}
}
Use of FromSql, FromSqlRaw, FromSqlInterpoated, ExecuteFunction, ExecuteStoreCommand, ExecuteStoryQuery, ExecuteStoreCommand, ExecuteSqlCommand and their Asynchronous counterpart results in the similar transaction as above.
Unknown SQL Query
protected void ResetWorkflowProgress(Entities context, DealerComplaint complaint)
{
context.Database.ExecuteSqlCommand(abcd);
complaint.LastDeciderName = null;
complaint.LastDecisionDate = null;
}
Reading of edmx file
edmx file mapping
internal void AddDataChangeApprover(DataChangeApprover dca)
{
_context.DataChangeApprovers.Add(dca);
}
DbContext and DbSet
public partial class DisplayConfigEntities : DbContext
{
public DisplayConfigEntities()
: base("name=DisplayConfigEntities")
{
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
throw new UnintentionalCodeFirstException();
}
public virtual DbSet<DataChangeApprover> DataChangeApprovers { get; set; }
}
edmx
<EntitySetMapping Name="DataChangeApprovers">
<EntityTypeMapping TypeName="DispalyConfiguration.DataChangeApprover">
<MappingFragment StoreEntitySet="Approval">
Support for Table Per Hierarchy
Table Per Hierarchy
public class AppDbContext : DbContext
{
public DbSet<CreditCard> CreditCard { get; set; }
public AppDbContext(DbContextOptions<AppDbContext> options) : base(options) { }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<BillingDetail>().ToTable("BankingBillingDetails");
}
}
public abstract class BillingDetail
{
[Required]
public int BillingDetailId { get; set; }
public string Owner { get; set; }
public string Number { get; set; }
}
public class CreditCard : BillingDetail
{
public int CardType { get; set; }
public string ExpiryMonth { get; set; }
public string ExpiryYear { get; set; }
}
Unknown Entity
Unknown Entity
public class BaseRepository<TEntity> : IRepository<TEntity>
where TEntity : class
{
private WP2AlertsContext alertsContext;
public BaseRepository(WP2AlertsContext wP2Context)
{
alertsContext = wP2Context;
}
public virtual async Task<TEntity> AddAsync(TEntity entity)
{
await alertsContext.AddAsync(entity);
alertsContext.Entry(entity).State = EntityState.Added;
await alertsContext.SaveChangesAsync();
return entity;
}
}
Repository and Unit of Work Pattern
Repository and Unit of Work Pattern
public partial class RepositoryPatternDemoContext : DbContext
{
public RepositoryPatternDemoContext()
{
}
public RepositoryPatternDemoContext(DbContextOptions<RepositoryPatternDemoContext> options)
: base(options)
{
}
public virtual DbSet<Customer> Customer { get; set; }
public virtual DbSet<Product> Product { get; set; }
}
public class CustomerRepository : Repository<Customer>, ICustomerRepository
{
public CustomerRepository(RepositoryPatternDemoContext repositoryPatternDemoContext) : base (repositoryPatternDemoContext)
{
}
public async Task<Customer> GetCustomerByIdAsync(int id)
{
return await GetAll().FirstOrDefaultAsync(x => x.Id == id);
}
}
Navigation Property Usage
Insert operation through navigation property
public class Entities : DbContext
{
public virtual DbSet<Brand> Brands { get; set; }
public virtual DbSet<Role_Brands> Role_Brands { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
throw new UnintentionalCodeFirstException();
}
}
public partial class Brand
{
public int Id { get; set; }
public string Name { get; set; }
public Nullable<int> AdditionApprovalId { get; set; }
public Nullable<int> DeletionApprovalId { get; set; }
public virtual ICollection<Role_Brands> Role_Brands { get; set; }
}
public class BrandAddition
{
protected void AssignRoleToBrand(Brand brand, int roleId, Entities context)
{
var entity = new Role_Brands()
{
BrandId = brand.Id,
RoleId = roleId,
AdditionApproval = ApprovalModel.CreateAdditionApproval(context, UserModel.GetCachedCurrentUser().Id)
};
brand.Role_Brands.Add(entity);
}
}
Assumptions
- SaveChanges() method of DbContext class commits the operation in the database table. Hence no useLink is created between caller method and table.
Limitations
- Unknown Entity object gets created in case the entity in the CRUD transaction does not get resolved. In such a case, the caller method will get connected to the Unknown Entity Operation object of the Unknown Entity.
- Unknown SQL Query object gets created if the query used in the execution does not get resolved.
- Limited support for “repository” and “unit of work” patterns