I have developed an app for tracking multi-party coordination on proposed change requests.
I only use two table, with a one-to-one relationship. One table correlates to fields on an existing official paper form, while the other table tracks additional information in a one-to-one relationship.
I previously developed this app as a standalone project, using MS Access, but now, I am adding the app to a "one-stop shopping" SQL Server database environment.
My problem comes in my DbSet statements. The table names which the DBA chose result in errors which I never had when the app was stand-alone:
Below is the C# code for the DbContext portion:
namespace FormTracker
{
public class ApplicationDbContext:DbContext
{
public ApplicationDbContext(DbContextOptions options) : base(options)
{
}
public DbSet<T__AODMS_1067_tracking_fields> T__AODMS_1067_tracking_fieldss { get; set; }
public DbSet<T__AODMS_1067_tracking_non_1067_fields> T__AODMS_1067_tracking_non_1067_fields_Recordss { get; set; }
}
}
The portions between the <> are what is being flagged when build is executed.
Any ideas? possibly something totally obvious that I'm not seeing?
Related
I'm building my first Razor Pages app by following Microsoft's tutorial, and I'm curious about the correct way to reflect changes to my model on CRUD/scaffolded pages and corresponding database table. I have used below steps to handle this, but my solution feels more like a hack. Is there a better way to do it? I'm looking for a dynamic solution which allows for better separation of concerns.
What I aim to do: I want to remove CVRnr from below model, have the corresponding column in the database table dropped, as well as removing references to CVRnr on pages. The problem is that my changes to the model isn't reflected dynamically elsewhere in the project.
namespace Virksomhedsgodkendelser.Models
{
public class Company
{
public int ID { get; set; }
public int Pnr { get; set; }
public int CVRnr { get; set; }
}
}
What I have done to solve this:
Deleted public int CVRnr { get; set; } from the model
Deleted the CRUD pages in ~/Pages/Companies/
Re-added the CRUD pages via: Add > New Scaffolded Item > Razor Pages using Entity Framework
Deleted dbo.Company from my database
Re-added the database table via Package Manager Console: Add-Migration InitialCreate + Update-Database
Im facing a problem that probably is quite common but i can't find any solution to it.
The problem occurs when a user has entities in its cache on the client and another user removes some of those entities (on the server). When the first user then wants to update its data the removed entities is not removed from the cache. You could solve it by clearing the cache each time you update but then you also looses all non-saved changes.
Am I missing something obvious?
Example:
Model:
public class Order
{
[Key]
public int Id { get; set; }
public ICollection<OrderDetail> OrderDetails { get; set; }
}
public class OrderDetail
{
[Key]
public int Id { get; set; }
[ForeignKey("Order")]
public int Order_Id { get; set; }
public virtual Order Order { get; set; }
}
Client code:
function getOrder(orderId, orderObservable) {
var query = EntityQuery.from("Orders")
.where("orderId", "==", orderId)
.expand("orderDetails");
return manager.executeQuery(query).then(querySucceeded).fail(queryFailed);
function querySucceeded(data) {
var order = data.results[0];
// NOTE: the removed orderdetail is still there 'order.orderDetails'
orderObservable(order);
}
}
Step-by-step scenario:
User A queries for an order with its corresponding orderdetails.
The order and orderdetails is then placed in the cache.
User B removes an orderdetail and saves the changes to the server.
User A queries to get the latest updates for the order.
When the query returns the removed orderdetail is still there.
In the breeze-docs, under the headline "Important Caveats about cache clearing", there is a solution that removes cached entities by comparing the cache and the result from the query and detaches the missing entities in the result.
http://www.breezejs.com/documentation/entitymanager-and-caching
But that doesn't work in this case. I'm guessing it has to do with the fact that orderdetails is related to the order and that it is "picked up" from the cache before it is passed to the success-callback.
All help is appreciated!
The problem you are facing isn't with Breeze, but with design in general. There are a couple of options that come to mind -
Use SignalR to notify your web application that a change has occurred, detach any removed entities from the cache.
Use an archived or deleted flag instead of removing the entities from the database.
Both have their advantages and disadvantages.
With SignalR you will need to get the pipe work in place for notifications and set up a specific work flow around removing deleted entities
manager.detachEntity(entityToDetach);
The reason you would detach instead of deleting is because if you set it to deleted then your Breeze entity manager still thinks you need to persist that change to the database.
If you use a flag then you could simply set your business logic to ignore entities that are flagged as deleted or archived and when you query the DB it will return the change to that entity and stop showing it
myEntity().archived(true);
The problem here would be if your entity doesn't match your query it would never return the updated entity to let the client know that it was archived or deleted. The other caveat is that you would have information laying around in your database that isn't active anymore.
Depending on which type of application and requirements you have you should make one of these choices, or come up with another. Hope that helps.
I originally asked this question when Identity was in beta. The classes and interfaces have changed considerably since then and it appears the RTW version has some modifications again over the RC version. In principle I need to achieve the following.
authenticate the local login against my usertable tblMembers which contains the userid field and password which are the two items I need to authenticate.
have access to my tblMember record/class via the Controller.User property (Prior to MVC5 identity I had achieved this using the membership provider methods.) regardless of if the user logged in via the localuser method or via one of the other OAuth providers (Twitter, Google etc).
Ability to display my own custom username despite the login method. Local users login with a userid 1234567 and a password, ideally I would like to display "John Smith (1234567)" regardless of the authentication method (local/Twitter etc)
Initially I'm unsure as to what my memberclass should be inheriting from It appears from the
aspIdentitySample project that I should be using IdentityUser?
public partial class tblMember
{
public int id { get; set; }
public string membership_id { get; set; }
public string password { get; set; }
....other fields
}
Are there any new or updated examples of integrating your existing database/user tables with the ASP.NET Identity system?
I am also adding the identity tables to my database. If you create a new web project in visual studio 2013 you will see that now in RTM everything works better than RC plus you will see the
following table
public class ApplicationUser : IdentityUser
{
}
So Instead of ApplicationUser you can call your table tblMembers
public class tblMembers : IdentityUser
{
}
your table tblMembers will inherit Id Username Password security stamp and a discriminator column saying this is a tblMemeber
without making custom classes for authentication the easiest thing to do would be just to make the username the combination of your old usernames and userids. Then store the users real name or old username without the user id in a separate column.
have the users register with the built in user login and they can go to manage account and click use another service to log in. This will link the Google account to their regular account, so no matter which one they use it will log them in to the same account. If you have users with connected table information, I suggest you seed your table with all the users with something similar to the register method found in the template.Then just match the new combined username and Id to the old ones and populate data where needed in sql management studio.
Again a lot of issues in RC with extending IdentityUsers have been fixed. Microsoft is already adding more features to the identity user store and this tutorial http://www.windowsazure.com/en-us/develop/net/tutorials/web-site-with-sql-database/ is supposed to be updated soon. I plan on making my own walk through when i'm done changing my database but for now I hope my suggestions even though they are a simpler solution than you might want to implement.
You can do this easily by modifying the IdentityModel.cs as per the below:
Override OnModelCreating in your DbContext then add the following, this will change AspNetUser table to "Users" you can also change the field names the default Id column will become User_Id.
modelBuilder.Entity<IdentityUser>()
.ToTable("Users", "dbo").Property(p => p.Id).HasColumnName("User_Id");
or simply the below if you want to keep all the standard column names:
modelBuilder.Entity<IdentityUser>()
.ToTable("Users", "dbo")
Full example below (this should be in your IdentityModel.cs file) i changed my ApplicationUser class to be called User.
public class User : IdentityUser
{
public string PasswordOld { get; set; }
public DateTime DateCreated { get; set; }
public bool Activated { get; set; }
public bool UserRole { get; set; }
}
public class ApplicationDbContext : IdentityDbContext<User>
{
public ApplicationDbContext()
: base("DefaultConnection")
{
}
protected override void OnModelCreating(System.Data.Entity.DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Entity<IdentityUser>()
.ToTable("Users", "dbo").Property(p => p.Id).HasColumnName("User_Id");
modelBuilder.Entity<User>()
.ToTable("Users", "dbo").Property(p => p.Id).HasColumnName("User_Id");
}
}
Please note i have not managed to get this working if the current table exists.
Also note whatever columns you do not map the default ones will be created.
Hope that helps.
I'm starting to think (partially due to the lack of information in this area), that it may be easier to user the default identity classes, but to provide referential integrity to my own user table from the AspNetUsers table.
If i add a custom linking field into the AspNetUsers table is it possible to access my tables from the Controllers.User property? i.e. Controller.User.tblMember.Orders?
Question is in the title. Can we programmatically change the database table which an object in the Model class, like one below, refers to and continue to operate on the new table?
public class Word
{
public int ID { get; set; }
public string Text { get; set; }
}
This originally refers to "Words" table automatically in EntityFramework, is there a way to change it before/during runtime? If so, how?
EDIT:
I get all the string used in Views in the project from the database table, "Words", by their ID's. Now, what I want is, a user enters a new language to system, and a new table will be created, for example WordsEnglish. From then, the Word object will refer to WordEnglish, if user selects English as language.
It would be desirable with a use case to better understand what you are trying to accomplish, but here goes...
In the DbContext.OnModelCreating method you can configure the model, e.g.
// Removes pluralization convention for all tables.
modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
or
// Specific table name for Word Entity.
modelBuilder.Entity<Word>().ToTable("TableContainingWords");
If you are changing your model, Code First Migrations might be what you need.
I havent found a way to truly dynamically extend an EF model at runtime. Given what goes on in DB context inherited class, the use of generated views for performance and a model class approach, avoiding recompilation seems hard. I have generated code, compiled and access this using assembly discovery approaches. But this is all unsatisfactory from my viewpoint , so i have stopped investigating this path. Very clunky outcome.
Ironically the topic you provide as a use case for such a problem, is one that doesnt need dynamic EF in my view.
I have exactly the same use case, language specific look for messages/labels etc Ie a language specific textpool.
Why not add language to the class/table.
Use a table or Enum for supported languages.
Use Language in the Textpool table/s
Use a different model class for presentation. (view model).
So you can present it the way like .
public class Word
{
Guid ID {get;set;} // logical key is WordID + Language
public int WordID { get; set; } // implement with new id or 2 field key
public Language Language {get;set;} // see cultureInfo for more details
public bool IsMaster {get;set;}
public string Text { get; set; } // consider renaming due to reserved word implications
}
public class language
{
int ID,
String Lang
}
}
Although I love what I'm learning, I'm finding it a struggle and need some help
I've been using these two tutorials which I think are awesome:
http://weblogs.asp.net/scottgu/archive/2010/07/16/code-first-development-with-entity-framework-4.aspx
http://msdn.microsoft.com/en-us/data/gg685467
Currently my main problem/confusion is:
I have a CodeFirst table/entity I don't know how to correctly get data from other tables/entities to show in my views:
public class Car {
public int ID { get; set; }
public string Name { get; set; }
public int EngineID { get; set; }
public virtual Engine { get; set; }
}
public class Engine {
public int ID { get; set; }
public string Name { get; set; }
public string Manufacturer { get; set; }
// (plus a whole lot of other things)
}
Now when I create a View for Cars (using the List type/option) I get a nice autogenerated list
#foreach (var item in Model) {
<tr>
<td>#item.ID</td>
<td>#item.Name</td>
<td>#item.EngineID</td>
</tr>
Perfect... except EngineID is mostly worthless to the viewer, and I want to show Engine.Name instead
So I assumed I could use EF lazy loading:
<td>#item.Engine.Name</td>
Unfortunately when I tried that, it says my ObjectContext has been disposed so can't get any further data requiring a connection
Then I tried going to the controller and including the Engine.Name
var cars = (from c in db.Cars.Include("Engine.Name") select c;
Which tells me: Entities.Engine does not declare a navigation property with the name 'Name'
... ? Lies
Include("Engine") works fine, but all I want is the Name, and Include("Engine") is loading a large amount of things I don't want
Previously in a situation like this I have created a view in the DB for Car that includes EngineName as well. But with CodeFirst and my noobness I haven't found a way to do this
How should I be resolving this issue?
I thought perhaps I could create a Model pretty much identical to the Car entity, but add Engine.Name to it. This would be nice as I could then reuse it in multiple places, but I am at a loss on how to populate it etc
Wanting to learn TDD as well but the above is already frustrating me :p
Ps any other tutorial links or handy things to read will be greatly appreciated
It isn't lies as you are actually trying to include a property that's a 2nd level down withouth giving it a way to navigate. If you let EF generate your DB with this structure, it would likely have made a navigation table called something like Car_Engine and if you include the name without the object it HAS mapped, then it's not got a navigation property in your new object.
The simple way around this is to go:
(from c in db.Cars.Include("Engine") select new { c, EngineName = c.Engine.Name }
If you still get navigation property errors then you might need to make sure your are mapping to your schema correctly. This can be done with EntityTypeConfiguration classes using the fluent API - very powerful.
This of course won't help in strongly typing your car object to show in MVC.
If you'd like to get around this, your gut feeling is right. It's pretty common to use viewmodels that are read only (by design, not necessarily set to readonly) classes that provide simple views of your data.
Personally I keep my model quite clean and then have another project with viewmodels and a presentation project to populate. I'd avoid using overlapping entities in your core model as it might lead to unpredictable behaviour in the data context and at least a peristance nightmare when updating multiple entities (ie who's responsible for updating the engine name?).
Using you viewmodels, you can have a class called CarSummaryView or something with only the data you want on it. This also solves the issue of being vulnerable to overposting or underposting on your site. It can be populated by the above query quite easily.
PS There's a bunch of advantages to using viewmodels beyond just not loading full heirarchies. One of the biggest is the intrinsic benefit it gives you with avoiding over and underposting scenarios.
There's loads of ways to implement viewmodels, but as a simple CarView example:
public class CarView
{
public int ID { get; set; }
public string Name { get; set; }
public string EngineName { get; set; }
}
This should be clearly seperated from your entity model. In a big project, you'd have a single viewmodels project that the presenter can return, but in a smaller one you just need them in the same layer as the service code.
To populate it directly from the query, you can do the following
List<CarView> cars = (from c in db.Cars.Include("Engine.Name") select new CarView() { ID = c.ID, Name = c.Name, EngineName = c.Engine.Name }).ToList();