I have the following context:
public class DataContext : DbContext
{
/// <summary>
/// Gets or sets Addresses.
/// </summary>
public DbSet<Address> Addresses { get; set; }
/// <summary>
/// Gets or sets Users.
/// </summary>
public DbSet<Users> Users { get; set; }
}
I my application user may change data in say user data and then he may want to cancel changes. The best way to do this, is to refresh the DataContext from the database. But DbContext has no Refresh method. How can I refresh my DataContext?
You can reload the entity from the database as follows.
context.Entry(user).Reload();
Or you can try out the methods described in this question.
Related
I'm running with the code below and I can see that one key is created in the table [DataProtectionKeys]
services.AddDataProtection()
.SetApplicationName(dataProtectionSettings.ApplicationName)
.ProtectKeysWithCertificate(serviceCertificate)
.UnprotectKeysWithAnyCertificate(serviceCertificate)
.PersistKeysToDbContext<DataProtectionContext>();
I'm using this database context (am I missing something?):
class DataProtectionContext : DbContext, IDataProtectionKeyContext
{
/// <summary>
/// A recommended constructor overload when using EF Core with dependency injection.
/// </summary>
/// <param name="options"></param>
public DataProtectionContext(DbContextOptions<DataProtectionContext> options)
: base(options) { }
/// <summary>
/// This maps to the table that stores keys.
/// </summary>
public DbSet<DataProtectionKey> DataProtectionKeys { get; set; }
}
But, if I change to ApplicationName string value to something else, I don't see that a new key is created
Any idea why or how to fix it so this database table can support multiple application
I currently design table for customer and staff for my ecommerce app and I am using asp.net core identity. I want to know if I should use 1 table user (aka aspnetuser) for staff and customer or should I separate them and use user id as foreign key? If separating them 2 new table with foreign key is user id, how can I use user manager for creating account for staff and customer?
Thanks.
You can extend the base IdentityUser class in order to create a table with additional fields, like:
public class MyIdentityUser : IdentityUser<string>
{
public string FirstName { get; set; }
public string LastName { get; set; }
public string Type { get; set; }
...
where the Type field could be Staff or Customer.
Or you can use one or more additional table and use the Id as defined in IdentityUser class from Microsoft.ASpNetCore.Identity:
public class IdentityUser<TKey> where TKey : IEquatable<TKey>
{
/// <summary>
/// Initializes a new instance of <see cref="IdentityUser{TKey}"/>.
/// </summary>
public IdentityUser() { }
/// <summary>
/// Initializes a new instance of <see cref="IdentityUser{TKey}"/>.
/// </summary>
/// <param name="userName">The user name.</param>
public IdentityUser(string userName) : this()
{
UserName = userName;
}
/// <summary>
/// Gets or sets the primary key for this user.
/// </summary>
[PersonalData]
public virtual TKey Id { get; set; }
...
you can define the type of your Id field, like my previous example, and use the same type on a related field (like IdentityUserId) in your custom table/tables.
If you extend the base IdentityUser class you need to create a derived context with this declaration, like this:
namespace MyProject.Infrastructure.Contexts
{
public class MyContext : IdentityDbContext<MyIdentityUser>
{
...
My application is using EF6 database first approach. All the entities in the database have 2 common properties "CreatedDateTime" and "ModifiedDateTime".
Currently When i do SaveChanges() im explicitly setting these 2 properties based on if i am creating new entity or updating existing entity.
If its a new entity then set both properties else set only ModifiedDateTime property.
I wanted to know if there is a way to implicitly set these 2 properties on Save or update operation?
Update 1
I know i have to override Savechanges() method however the real issue here is SaveChanges needs to have access to these 2 properties. So i only see 2 options here:
1> Use reflection to find if entity has these properties and set it.
2> Modify default T4 generation so that it derives all entities with predefined interface. And this interface will have these 2 properties. SaveChanges() method can check if entity is derived from this interface and set the property.
I defiantly don't want to use option 1 using refection.
Is there any other way or has anyone done this before in DB first approach?
Going with your second approach: Adjust your T4 files to include a reference to an interface (e.g. IChangeTrack):
public interface IChangeTrack
{
/// <summary>
/// When has this entry be created
/// </summary>
[Required]
DateTime CreatedDateTime { get; set; }
/// <summary>
/// When has this entry been modified
/// </summary>
DateTime? ModifiedDateTime { get; set; }
}
Now overwrite your SaveChanges() routine by doing something like this:
/// <summary>
/// Enhance save changes to handle system fields.
/// </summary>
/// <returns></returns>
public override int SaveChanges()
{
HandleChanges();
int changes = base.SaveChanges();
return changes;
}
public override async Task<int> SaveChangesAsync(CancellationToken cancellationToken)
{
HandleChanges();
int changes = await base.SaveChangesAsync(cancellationToken);
return changes;
}
private void HandleChanges()
{
ChangeTracker.DetectChanges();
var entries = ChangeTracker.Entries<IChangeTrack>();
if (entries != null)
{
foreach (DbEntityEntry<IChangeTrack> entry in entries)
{
switch (entry.State)
{
case EntityState.Added:
entry.Entity.CreatedDateTime = DateTime.UtcNow
break;
case EntityState.Modified:
entry.Entity.ModifiedDateTime = DateTime.UtcNow;
break;
}
}
}
}
I have an inheritance hierarchy setup that I am mapping to a DB via TPT in Code first. For the most part the hierarchy is one level deep, but sometimes it it two. My base class looks like this:
public class AuditEvent
{
public int AuditEventID;
//other stuff
};
Then I have a bunch of other classes that look like this (with different names and properties):
public class PageRequest : AuditEvent
{
/// <summary>
/// Page Request Id (Primary Key)
/// </summary>
public Int64 PageRequestID { get; set; }
/// <summary>
/// Screen (page) being requested
/// </summary>
public string Screen { get; set; }
/// <summary>
/// Http Method
/// </summary>
public string HttpMethod { get; set; }
/// <summary>
/// Confirmation Logs linked to this page request
/// </summary>
public virtual List<ConfirmationLog> ConfirmationLogs { get; set; }
}
This specific class (PageRequest) is a parent to one other class called ConfirmationLog, which looks like this:
/// <summary>
/// Object used to log confirmations to the auditing database
/// </summary>
public class ConfirmationLog : PageRequest
{
/// <summary>
/// Confirmation ID
/// </summary>
public long ConfirmationID { get; set; }
/// <summary>
/// Confirmation number
/// </summary>
public string ConfirmationNum { get; set; }
/// <summary>
/// Web action ID (automated alert or transaciton confirmation number)
/// </summary>
public int WebActionID { get; set; }
}
I'm configuring the mappings using configuration classes and the fluent API, like so:
/// <summary>
/// Configuration class for PageRequest
/// </summary>
public class PageRequestConfiguration : EntityTypeConfiguration<PageRequest>
{
/// <summary>
/// Default constructor
/// </summary>
public PageRequestConfiguration()
{
//Table
ToTable("PageRequests");
//primary key
HasKey(a => a.PageRequestID);
//Properties
Property(a => a.PageRequestID).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
Property(a => a.Screen).IsRequired().HasMaxLength(100);
Property(a => a.HttpMethod).IsRequired().HasMaxLength(10);
}
}
/// <summary>
/// Confirmation Log configuration class. Configures the confirmation log class for the db model
/// </summary>
public class ConfirmationLogConfiguration : EntityTypeConfiguration<ConfirmationLog>
{
/// <summary>
/// Default constructor
/// </summary>
public ConfirmationLogConfiguration()
{
//Map to Table
ToTable("ConfirmationLogs");
//Primary Key
HasKey(a => a.ConfirmationID);
//required fields
Property(a => a.ConfirmationID).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
Property(a => a.PageRequestID).IsRequired();
Property(a => a.ConfirmationNum).IsRequired().HasMaxLength(12);
Property(a => a.WebActionID).IsRequired();
}
}
I then create a rather large LINQ query based on this hierarchy. I'll spare that query because it's composed in about 10 steps, and I don't think that's the source of my problem. The problem is, when I run the query, the SQL generated for some reason thinks that the column AuditEventID (the primary key for the base class), exists on the ConfirmationLogs table (the grandchild table). The ConfirmationLogs table has a foreign key to it's parent table (PageRequests), which then has the foreign key to it's parent table (AuditEvents).
My question is, did I set this hierarchy up wrong? Does the "grandchild" table need the foreign key to both it's parent and grandparent for this to function? (if it does I find that unfortunate).
I'm positive that the inheritance relationship is throwing things off because if I don't make ConfirmationLogs a child of PageRequests and configure the relationship to PageRequests with HasRequired()/WithMany(), things work fine.
Any help would be appreciated.
Update
So, after further investigation I think there is a general problem with the way I'm trying to use inheritance. I should note that I'm trying to map code first to an existing database. In the database, I have my AuditEvent table, and a bunch of "child" tables like PageRequest. Page request has it's own primary key called PageRequestID, as well as a foreign key called AuditEventID. The other child tables are setup the same way. In my Configuration class for PageRequest (listed above), I'm trying to map this by using the HasKey function to say that the PageRequestID is the primary key, and assuming that EF will know about the foreign key AuditEventID by convention and inheritance. I should also note that I can write to the DB using the model just fine. If I want to write a PageRequest, I create PageRequest object, populate all the required fields as defined by both the PageRequest and AuditEvent base class, and save through the context. EF creates the AuditEvent record, and the pageRequest record with the FK back to AuditEvent.
What makes me think I'm not using inheritance right is that I allowed EF to create my database for me, using the model and mapping I've created. For the PageRequest table (and all other child tables), EF actually created a primary key called AuditEventID (even though my configuration is telling it to do otherwise). This key is also labeled as a foreign key, and the column that I want to create as a primary key (PageRequestID in this example) is just configured as being required (non-nullable). So it appears that EF taking the primary key from my BASE class and using that as a primary key AND foreign key in my child classes, almost like the concept of the AuditEventID is spread between the parent and child tables. Is there a way to change this behavior?
You are saying this didn't work, and it still expected an AuditRequestID in the table that had the ConfirmationLog object? I'm looking at the reference: Specifying Not to Map a CLR Property to a Column in the Database in http://msdn.microsoft.com/en-us/data/jj591617#1.6
public ConfirmationLogConfiguration()
{
//Map to Table
ToTable("ConfirmationLogs");
//Primary Key
HasKey(a => a.ConfirmationID);
//required fields
Property(a => a.ConfirmationID).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
Property(a => a.PageRequestID).IsRequired();
Property(a => a.ConfirmationNum).IsRequired().HasMaxLength(12);
Property(a => a.WebActionID).IsRequired();
Ignore(a => a.AuditEventID);
}
Good luck.
LINQ "include" missing. after reading this post:
http://romiller.com/2010/07/14/ef-ctp4-tips-tricks-include-with-lambda/
i would like to use include.
this is my class:
public class Service
{
#region Properties
/// <summary>
/// Gets or sets CatalogRootNodeId.
/// </summary>
public virtual int CatalogRootNodeId { get; set; }
/// <summary>
/// Gets or sets ServiceDomain.
/// </summary>
public virtual ICollection<ServiceDomain> ServiceDomain { get; set; }
#endregion
}
I would like to "Include" all ServiceDomains but "Include" option is not there
??
I'm working with MVC3 and EF.
thanks
Are you using CTP5 or CTP4?
If you do, you can use the extension method from System.Data.Entity.DbExtensions.Include.
public static IQueryable<T> Include<T>(this IQueryable<T> source, Expression<Func<T, object>> path)
var db = new MyDbContext();
var services = db.Services.Where(s => s.CatalogRootNodeId == 1).Include(s => s.ServiceDomain);
You need to call Include() on the ObjectSet<Service> from the DataContext.