I am developping a web site to learn AspNetCore.
I use AspNetRoles and AspNetUserRoles tables,
I started with Vs2015 and ASpNet.Core 1.1 and I achieve to retrieve the list of roles and the numbers of users associated to each role with this code
model = roleManager.Roles.Select(r => new ApplicationRoleListViewModel
{
RoleName = r.Name,
Id = r.Id,
Description = r.Descricao,
NumberOfUsers = r.Users.Count
}).ToList();
Today I downloaded the final release of VisualStudio 2017 Community, and when I lunch the web app, I have an error to retrieve the list of roles,
An unhandled exception occurred while processing the request.
InvalidOperationException: No value provided for required parameter '_outer_Id'.
Microsoft.EntityFrameworkCore.Storage.Internal.RelationalCommand.CreateCommand(IRelationalConnection connection, IReadOnlyDictionary<string, object> parameterValues)
The problem now, seems to be NumberOfUsers = r.Users.Count
What do I need to change in my code to work?
Related
I'm aiming to show virtual entity records on a subgrid on the form of a custom entity (say, Client). I have created a virtual entity, custom data provider and registered the required plugin. So far things work fine; I load the form, subgrid loads with the data from external webservice.
Now, I want to pass a string field on the form (say, Client.ExternalId) as a parameter to the retrieveMultiple plugin so that I can use this field to query the datasource.
The retriveMultiple plugin steps (registered automatically when custom data provider was set up) show that it was registered on the virtual entity and not Client entity. Since it gets executed on load of the subgrid on the Client entity form I am not sure how I can pass a field to the plugin.
Can someone please give some guidance on how to achieve this?
Version 1710 (9.2.22103.194) online
Thanks
If the virtual entity has an N:1 relationship with the main entity and the subgrid is configured to show related records, then you can do like this:
// first, get the whole query
var query = context.InputParameterOrDefault<QueryExpression>("Query");
// next, get the linkEntity and then the linkFilter
var linkFilter = query.LinkEntities.FirstOrDefault(x => x.LinkToEntityName == "mainEntityLogicalName").LinkCriteria;
// next, get the main entity id
var mainEntityId = linkFilter.Conditions.FirstOrDefault(x => x.AttributeName == "mainEntityIdFieldName").Values.FirstOrDefault() as Guid?;
// finally, retreive main entity to get the Client.ExternalId
var mainEntity = orgSvc.Retrieve("mainEntityLogicalName", mainEntityId.Value, new ColumnSet("Client.ExternalId"));
var clientExternalId = mainEntity.GetAttributeValue<string>("Client.ExternalId");
I'm trying to implement the ASP .NET Core Identity with PostgreSQL. I'm also trying to migrate the database programmatically. The code I'm trying to use, looks like this:
using var scope = _serviceProvider.CreateScope();
var context = scope.ServiceProvider.GetRequiredService<ApplicationDbContext>();
await context.Database.MigrateAsync();
This will be called at the start up at Program.cs. I'm facing this issue where the ASP Identity tables were created but the exception Npgsql.PostgresException: '42P07: relation "AspNetRoles" already exists' was also thrown. What did I do wrong?
The reason for you are getting the exception is because the table AspNetRoles already exists in the database.
You can use the following code to check if there are any pending migrations and if there are any then execute the MigrateAsync() method:
var pendingMigrations = await context.Database.GetPendingMigrationsAsync();
if (pendingMigrations.Any())
{
await context.Database.MigrateAsync();
}
Read more about applying migrations automatically here: https://makolyte.com/ef-core-apply-migrations-programmatically/
Update based on comments
A good resource for getting started with migrations: https://www.learnentityframeworkcore.com/migrations
Like several others I have tried to implement ASP.NET Identity Model First. Everything works fine once you have tried, errored, fumed, searched and resolved.. I thought.
See also:
ASP.NET Identity with EF Database First MVC5
http://danieleagle.com/blog/2014/05/setting-up-asp-net-identity-framework-2-0-with-database-first-vs2013-update-2-spa-template/
Course of action, summarized:
Created default project (MVC5)
Create database
Update connectionstring in the web.config
Run website, register: tables get created
Create EF Model (edmx)
Import Identity tables (everything fine up to this point)
Modified xxx.Context.tt to inherit from IdentityDbContext
Generate database script (trouble starts here)
I have solved the issues that appeared (up to the latest step). For completeness I will describe them.
Using the default Identity context
Everything works fine: tables get created, I can Register and login. This is however not the situation I want: I want to use a Model First approach.
Using the custom, model first context using the EF connectionstring
Modifying the CreatePerOwinContext so that it uses my Model First context:
public void ConfigureAuth(IAppBuilder app)
{
app.CreatePerOwinContext(CustomModelFirstDbContext.Create);
And the ApplicationUserManager so that it uses the Model First context:
public static ApplicationUserManager Create(IdentityFactoryOptions<ApplicationUserManager> options, IOwinContext context)
{
var manager = new ApplicationUserManager(new UserStore<ApplicationUser>(context.Get<CustomModelFirstDbContext>()));
Results in:
Server Error in '/' Application.
The entity type ApplicationUser is not part of the model for the
current context.
Description: An unhandled exception occurred during the execution of
the current web request. Please review the stack trace for more
information about the error and where it originated in the code.
Exception Details: System.InvalidOperationException: The entity type
ApplicationUser is not part of the model for the current context.
Source Error:
An unhandled exception was generated during the execution of the
current web request. Information regarding the origin and location of
the exception can be identified using the exception stack trace below.
Stack Trace:
[InvalidOperationException: The entity type ApplicationUser is not
part of the model for the current context.]
Using the "normal" connectionstring with the custom, Model First context
An exception of type
'System.Data.Entity.Infrastructure.UnintentionalCodeFirstException'
occurred in WebApplication1.dll but was not handled in user code
Additional information: Code generated using the T4 templates for
Database First and Model First development may not work correctly if
used in Code First mode. To continue using Database First or Model
First ensure that the Entity Framework connection string is specified
in the config file of executing application. To use these classes,
that were generated from Database First or Model First, with Code
First add any additional configuration using attributes or the
DbModelBuilder API and then remove the code that throws this
exception.
So, I figured I needed the default Identity context to use Identity, and use the custom Model First context for everything else. Not the preferred solution, but acceptable.
Rolled everything back
Import Identity tables from database
(Optional) Created entities via the Model First approach
Generated database script
Both the normal project and a quick sanity check test project have the same problem with the AspNetUserRoles table. That is a junction table, and when importing it in the EF designer, everything is OK. You won't see it since it is a many to many relationship, and when inspecting the association between AspNetRole and AspNetUser it looks good.
Designer and mapping details:
However, when generating the sql script, EF modifies the keys.
Designer and mapping details:
Generated SQL script:
-- Creating table 'AspNetUserRoles'
CREATE TABLE [dbo].[AspNetUserRoles] (
[AspNetRoles_Id] nvarchar(128) NOT NULL,
[AspNetUsers_Id] nvarchar(128) NOT NULL
);
GO
In EF, you can't change the names of the mappings in the designer (thread on social.msdn.microsoft.com).
Subsequently the creation of a new user wil fail, using the originally created context because the junction table contains the wrong columns:
Server Error in '/' Application.
Invalid column name 'UserId'.
Invalid column name 'UserId'.
Invalid column name 'UserId'.
Invalid column name 'RoleId'.
Invalid column name 'UserId'.
Description: An unhandled exception occurred during the execution of
the current web request. Please review the stack trace for more
information about the error and where it originated in the code.
Exception Details: System.Data.SqlClient.SqlException: Invalid column name 'UserId'. Invalid column name 'UserId'. Invalid column name 'UserId'. Invalid column name 'RoleId'. Invalid column name 'UserId'.
Source Error:
Line 89: {
Line 90: var user = new ApplicationUser() { UserName = model.Email, Email = model.Email };
Line 91: IdentityResult result = await UserManager.CreateAsync(user, model.Password);
Line 92: if (result.Succeeded)
Line 93: {
What is the solution? Are there any alternatives than trying to change the generated script, or moving to Code First?
If you in the begginning and db is still empty than
I believe the easiest workaround is:
Create EF Model(edmx).
Right click on model "Generate Database from model".
It will create DDL file (snippet below)
Replace all wrong "AspNetUsers_Id" and "AspNetRoles_Id" for correct values.
Right click "execute".
Works for me.
-- Creating non-clustered index for FOREIGN KEY 'FK_AspNetUserRoles_AspNetUser'
CREATE INDEX [IX_FK_AspNetUserRoles_AspNetUser]
ON [dbo].[AspNetUserRoles]
([AspNetUsers_Id]); //replace for UserId
Happy coding!
I've just started working with Web API this week, and I'm struggling with something which I think should be quite simple, but haven't been able to find the answer for yet. Perhaps I'm searching using the wrong terms.
One of the calls to the API passes through a GUID. I need to create a new entity (using Entity Framework) and set one of the relations to this newly passed in GUID. This GUID is the ID of a different entity in the database.
I'm struggling to attach the entity via the relation without fetching the whole entity too.
For example,
public void DoWork(IList<Guid> userGuids)
{
Order order = new Order() // This is an entity
{
CreateDate = DateTime.Now,
CreatedBy = "Me",
Items = (from i in this.Model.Items
where i.Id == userGuid
select i).ToList<Item>();
}
Model.Orders.Add(order);
Model.SaveAll();
}
In the above, I have to do a database call to attach the Item entities to the Order. Is there not a way around this? Seems very redundant to retrieve the whole entity objects when I only require their IDs (which I already have anyway!)!
One solution is stub entities as asked here: Create new EF object with foreign key reference without loading whole rereference object
Link to the source blog referenced: http://blogs.msdn.com/b/alexj/archive/2009/06/19/tip-26-how-to-avoid-database-queries-using-stub-entities.aspx
Snip from the blog - to be applied to your situation:
Category category = new Category { ID = 5};
ctx.AttachTo(“Categories”,category);
Product product = new Product {
Name = “Bovril”,
Category = category
};
ctx.AddToProducts(product);
ctx.SaveChanges();
This way (in the example) the Product is saved without ever loading the Category object.
I am fairly new to ADO.NET. I am ok with all the basic INSERT, etc. But now, I have a problem inserting a record into a table that contains a foreign key. I have done some research but am still stuck ... so here goes:
I want to INSERT a new record into a table called Professionals. It has a foreign key mapped to a different table. The FK is WAPublicUserID.
See Image:
When I create a data model, the WAPublicUserID isn't listed in the Properties of the Professional data model.
See Image:
Therefore, when I try to create an INSERT in my code, the WAPublicUserID field can't be found and I can't insert the record. The WAPublicUserID that I wish to use already exists in the WAPublicUser table that the FK is mapped to.
See Image:
How do I go about Inserting a new record in the Professionals table that contains a foreign key to an existing record in the WAPublicUser table? Thanks!
Someone has set "Include Foreign Key Properties in Model" to false.
Hence you have the navigation property of WAPublicUser but not the ForeignKey property.
This means you will have to Attach the relevant WAPublicUser object to the WAPublicUser property on the object you are trying to save.
I'd need a lot more code to know exactly what you are doing, but the basics of it are as follows:
If the WAPublicUser already exists:
Grab the existing entity from the database - OldEntity.
Update the OldEntity with the properties of the new one you are currently trying to save.
Save the (now updated) Old entity back to the database - because you have just read it, it should have the WAPublicUser reference already set.
If it doesn't:
Create a new WAPublicUser
Set the WAPublicuser property of the Professional object to the newly created WAPublicUser - that line goes where your code stops above.
myEnt.AddToProfessionals(pro);
myEnt.SaveChanges();
Got it. Here's how it works, in case anyone else reads this. #1 and #2 are focal points.
Mucho thanks to #BonyT for getting me on the right path ...
using (JONDOEntities myEnt = new JONDOEntities())
{
// #1) Need to create WAPublicUser object first
var wap = (from w in myEnt.WAPublicUsers
where w.WAPublicUserID == 981
select w).FirstOrDefault();
var proUser = (from p in myEnt.Professionals
where p.WAPublicUser.WAPublicUserID == wap.WAPublicUserID
select p).FirstOrDefault();
// If the record does not exist in the Professional table, insert new record.
if (proUser == null)
{
JONDOModel.Professional pro = new JONDOModel.Professional()
{
ProfessionalType = "unknown",
FirstName = "unknown",
LastName = "unknown",
PhoneNumber = "unknown",
WebsiteUrl = "unknown",
TaxID = "unknown",
BusinessInfo = "unknown",
ProfessionalLogo = "unknown",
IsApproved = true,
CATaxExempt = false,
WAPublicUser = wap // #2) Plug in the WAPublicUser object here
};
myEnt.AddToProfessionals(pro);
myEnt.SaveChanges();
}
OK, here's the real answer to my OP:
The asp.net website that I took over to manage was targeting .NET 3.5. Apparently, there are some issues with 3.5 and Entity Framework.
I converted the website to target .NET 4.0(*see below to see how). When I went to create the entity data model, voila , by default, it now included the Foreign Keys and therefore, I did not have any issues as described in OP.
If you run into this situation, you have to make sure that the web server is also upgraded to .NET 4.0. Because if you upgrade/convert the website files to target .NET 4.0, but your web server hasn't been upgraded, then although the website runs smooth on your dev machine (assuming that it has .NET 4.0 framework), it will crash on the live web server.
As an aside, .NET 4.0 framework will run apps that were built using previous versions of .NET (backward compatibility) ... however, an app that targets .NET 4.0 will not run in an environment with .NET 3.5 framework or prior.
CONVERT WEBSITE TO .NET 4.0:
Two ways to convert/upgrade website to .NET 4.0. 1) Usually, when you open a fresh copy and it's targeting 4.0, visual studio will ask if you want to convert/upgrade (Choose YES). 2) Within visual studio (commercial version), click WEBSITE tab, START OPTIONS, BUILD ... then you should see the options to change the "Target Framework" ...