Entity Framework With Database - asp.net-mvc

Here are the entities that i have...
Public Class Account
Public Property AccountId As integer
Public Property AccountDescription As String
Public Property Transactions As List(Of Transaction)
End Class
Public Class Transaction
Public Property TransactionId As Integer
Public Property AccountId As Integer
Public Property TransactionDescription As String
End Class
i would like to make it suc that when i do "db.Account.find(1)" for example it also loads in the list of all transactions which have the coresponding AccountId. I'm not too sure what type of relationship this is?? anyway, right now i can do
Dim acct As Account = db.Account.Find(1)
acct.Transactions = from ts in db.transactions select ts where ts.AccountId = acct.accountid
but i know this is not the correct way, there must be a way to map this out so that entity can just load everything in one shot right? Thanks for any help.

You can use db.Account.Include("Transactions").SingleOrDefault(1) or put Transactions as virtual (I think it is Overridable in vb).

Related

Entity framework 6, fluent mapping of 1 to 0..1 relationship on non-primary-key columns

I'm trying to migrate an objectcontext/edmx system to dbcontext (EF6) with fluent mapping. I have a few instances like the following. Principal table has a relationship to a dependent table where a non-PK column in the dependent table holds the value of a PK column in the principal. On its own this would be a one to many relationship, but there is a unique index on the dependent table FK columns. Using EDMX mapping, this works fine as long as you define the relationship using mapping rather then referential constraints. Below is an executable example - you don't need the database because it doesn't get that far, currently:
Imports System.Data.Entity
Imports System.Data.Entity.ModelConfiguration
Module Module1
Sub Main()
Using session As New SaturnEntities
Dim res = session.BookingLegSet.Select(Function(x) New With {x.Prefix, x.ID, x.AddressDetails.Address}).ToList
End Using
End Sub
End Module
Partial Public Class BookingLeg
Public Property Prefix As String
Public Property ID As Integer
Public Property LegIndex As Integer
Public Overridable Property AddressDetails As BookingLegAddress
End Class
Partial Public Class BookingLegAddress
Public Property Prefix As String
Public Property ID As Integer
Public Property Address As String
Public Overridable Property BookingLeg As BookingLeg
Property JobLegPrefix As String
Property JobLegID As Integer?
End Class
Public Class BookingLegConfig
Inherits EntityTypeConfiguration(Of BookingLeg)
Public Sub New()
ToTable("JobLegs", "dbo")
HasKey(Function(x) New With {x.Prefix, x.ID})
HasOptional(Function(x) x.AddressDetails).WithRequired(Function(x) x.BookingLeg).Map(Function(x) x.MapKey("Prefix", "ID"))
End Sub
End Class
Public Class BookingLegAddressConfig
Inherits EntityTypeConfiguration(Of BookingLegAddress)
Public Sub New()
ToTable("JobAddresses", "dbo")
HasKey(Function(x) New With {x.Prefix, x.ID})
HasRequired(Function(x) x.BookingLeg).WithOptional(Function(x) x.AddressDetails).Map(Function(x) x.MapKey("JobLegPrefix", "JobLegID"))
End Sub
End Class
Partial Public Class SaturnEntities
Inherits DbContext
Public Sub New()
MyBase.New("data source=dbSaturn;initial catalog=Saturn;integrated security=True;MultipleActiveResultSets=True;")
End Sub
Protected Overrides Sub OnModelCreating(modelBuilder As DbModelBuilder)
modelBuilder.Configurations.Add(New BookingLegConfig)
modelBuilder.Configurations.Add(New BookingLegAddressConfig)
End Sub
Public Overridable Property BookingLegAddressSet() As DbSet(Of BookingLegAddress)
Public Overridable Property BookingLegSet() As DbSet(Of BookingLeg)
End Class
BookingLeg is the principal entity and BookingLegAddress is the dependant. JobLegPrefix and JobLegID in the dependent will be either null or will hold the Prefix and ID values from a BookingLeg record. When you run this you get an error that AddressDetails has been configured with conflicting mapping information. I've tried numerous different ways to map this, but haven't got anywhere - can anyone tell me what I need to do?
Remove the
HasOptional(Function(x) x.AddressDetails).WithRequired(Function(x) x.BookingLeg).Map(Function(x) x.MapKey("Prefix", "ID"))
line from BookingLegConfig class. Every single relationships must be configured only once in a single place (part of the configuration of any of the two involved entities, but not in both). In this particular case you should keep the second configuration inside BookingLegAddressConfig class
HasRequired(Function(x) x.BookingLeg).WithOptional(Function(x) x.AddressDetails).Map(Function(x) x.MapKey("JobLegPrefix", "JobLegID"))
because it specifies the correct FK column names.
Also EF6 does not support explicit FK columns for this type of relationship - no HasForeignKey fluent API, and MapKey is for specifying shadow property (and column) names. So additionally remove the JobLegPrefix and JobLegID properties from the BookingLegAddress class:
Partial Public Class BookingLegAddress
Public Property Prefix As String
Public Property ID As Integer
Public Property Address As String
Public Overridable Property BookingLeg As BookingLeg
End Class

Entity Framework Code First : One-To-One association using Annotations

I am having .NET MVC 5 and Identity...
I am trying to get a one to one relationship for my Member class to my MemberInfo class..
So, My classes looks something like this:
IdentityUser is in the Microsoft.AspNet.Identity.EntityFramework namespace with string Id as its ID.
public class GRNUser : IdentityUser {
....
....
}
public class MemberUser : GRNUser {
public virtual Member MemberInfo {get; set; }
}
public class Member {
public int ID {get; set; }
public string MemberUserID {get; set; }
public virtual MemberUser MemberUser { get; set; }
}
In my Context, I have this
modelBuilder.Entity<Member>().HasRequired(m => m.MemberUser)
.WithOptional(u => u.MemberInfo);
So, the MemberUser and Member should be able to navigate to and from each other using the MemberUser's ID property and Member's MemberUserID property.
However, when my Database is created, it has an additional column "MemberUser_Id" instead of using my MemberUserID that I specified. How do I make it use "MemberUserID" that I specified?
I've tried using a few combination so of the ForiegnKey Data Annotation, but keeps on getting this error:
Member_MemberUser_Source: : Multiplicity is not valid in Role 'Member_MemberUser_Source' in relationship 'Member_MemberUser'. Because the Dependent Role properties are not the key properties, the upper bound of the multiplicity of the Dependent Role must be '*'.
I don't know whether i understood you right or not, but i'l do my best to help.
(I'l assume that you work with code first migration)
If you want to make a one-to-one relation, why not try to make a standalone entity for your info which will have a foreign key for the user entity and that foreign key will be annotated as the primary key of the entity?
Another way is why just not add whatever attributes you like to the Application User entity and work with it?
In any case i might have misunderstood your purpose, so please feel free to explain further since your post is a bit confusing.

MVC Entity Framework invalid column name

I have been working with MVC 4 and Entity Framework to create a web app recently. Things have been going well with my database "ppProject" model, as shown here:
Public Class ppProject
<Key()>
Public Property ProjectID As Integer
Public Property ClientID As Integer
Public Property ProjectTitle As String
Public Overridable Property Client As ppClient
Public Overridable Property Milestones As ICollection(Of ppMilestone)
Public Overridable Property Tasks As ICollection(Of ppTask)
End Class
The problem is that I am adding a new table of employees, "ppEmployees". This way the Project can have a ProjectManager, which is a foreign key into the Employees table. These are the new models where ProjectManagerID (foreign key) is linked to EmployeeID (primary key):
Public Class ppProject
<Key()>
Public Property ProjectID As Integer
Public Property ClientID As Integer
Public Property ProjectTitle As String
Public Property ProjectManagerID As Integer 'NEW'
Public Overridable Property Client As ppClient
Public Overridable Property Milestones As ICollection(Of ppMilestone)
Public Overridable Property Tasks As ICollection(Of ppTask)
Public Overridable Property ProjectManager As ppEmployee 'NEW'
End Class
Public Class ppEmployee
<Key()>
Public Property EmployeeID As Integer
Public Property DepartmentID As Integer
Public Property FirstName As String
Public Property LastName As String
Public Overridable Property ProjectsInManagement As ICollection(Of ppProject)
Public Overridable Property TimeItems As ICollection(Of ppTimeItem)
Public Overridable Property Department As ppDepartment
End Class
When I change my project model and add the employee model, I am getting the error
Invalid column name 'ProjectManager_EmployeeID'
The line of code that is triggering this is when I first access my projects in a view with:
#For Each proj In client.Projects
Any ideas at what is causing this? This must be a naming convention problem or something simple because I haven't had any errors with any of my other table models prior to this.
EDIT - See my answer below. Very confused about what Entity Framework is doing here.
In Entity Framework the name of the field must match the name of the column.
otherwise EF wouldnt know how to map the fields unless you decorate the property with the column attribute like you did in your answer.
Ok I think I've fixed this. I had to make the following changes to the "ppProject" class:
<Column("ProjectManagerID")>
Public Property EmployeeID As Nullable(Of Integer) 'Has to be set, dont know why
If anyone knows why my property has to be named EmployeeID, please let me know. I'm very curious.
I had a similar problem about a month ago. I dropped the table and created a new one and the problem was solved. that is after i have tried other ways that did not work

Saving reference properties with just the foreign key in Entity Framework

I am sure this question has been asked before, so I apologize in advance, but am not sure of the correct keywords to include in my searches...
I am having trouble understanding the proper pattern for updating (or even inserting) an object when one of its properties is a collection of other properties in a disconnected environment (like a website). My issue has to do with the idea that a web application is only returning a collection of id's as opposed to the full object. I think the best way to explain this is with code snippets.
Given the following objects
Public Class User
Public Property UserId As Integer
Public Property Username As String
Public Property Roles As ICollection(Of Role)
End Class
Public Class Role
Public Property RoleId As Integer
Public Property RoleName As String
Public Property Users As ICollection(OF User)
End Class
Public Class EFDbContext
Inherits Entity.DbContext
Public Property Users As Entity.DbSet(Of User)
Public Property Roles As Entity.DbSet(Of Role)
End Class
A database is created with 3 tables - Users, Roles, and RoleUsers.
I know I can easily do the following
Dim db = New EFDbContext()
Dim r1 = New Role() With { .RoleName = "User" }
Dim r2 = New Role() With { .RoleName = "Admin" }
db.Roles.Add(r1)
db.Roles.Add(r2)
Dim u1 = New User() With { .UserName = "test1", .Roles = New List(Of Role) }
u1.Roles.Add(r1)
db.Users.Add(u1)
db.SaveChanges()
And it will save both new roles to the database (giving them RoleId values of 1 and 2 respectively), a new user (giving it a UserId value of 1) and a new Role-User entry with RoleId 1 and UserId 1.
However, when dealing with a disconnected scenario like a website, most people would have a View Model to represent the input from the user which then gets mapped back to the Entities. In addition, for values representing the Roles, the data coming back would most likely only contain the unique key representing the Role. For example,
Public Class UpdatedUserViewModel
Public Property UserId As Integer
Public Property Username As String
Public Property RoleIds As ICollection(Of Integer)
End Class
...
...
Dim userEntity = db.Users.Find(user.Values.UserId)
AutoMapper.Mapper.Map(userValues, userEntity)
So while the userEntity.Roles collection may contain a single item, the mapper probably just added the entry with something like
ForMember(Function(u) u.Roles, Sub(m) m.MapFrom(Function(su) su.RoleIds.Select(Function(r) New Role() With {.RoleId = r})))
And now we come to the problem, when the SaveChanges() method is called, EF throws a Validation error because the .RoleName property is Nothing.
How does this situation get handled? Are we supposed to manually loop through the Roles and fetch each one from the database? Can we not use mapping tools? Do I give bogus values for the "missing" properties and then loop through and mark them as Unchanged?
I know this was long but I thought the walk-throughs would be helpful...
Thanks.
You can use this algorithm
Start with the root entities.
For each root entity, e.g. a of type A, set a's properties except for navigation properties (at least all the mandatory ones (non-nullables))
Add the As to the context.
Next prepare child entities (entities that must have exactly 1 A) e.g. b of type B.
Set b's properties (except navigations, at least all non-nullables).
For each b, add b to its a (e.g. a.Children.Add(b)).
Continue with child entities of above
...
Save and apply changes
If you have an entity with a non-nullable navigation that already exists in DB and has not yet been accessed via context, you can set the relationship by ID (assuming you've mapped the FK to a property in the model) instead of setting the entity itself.
If your IDs are not store generated, make sure you set them too. If they are, make sure they are defined as store generated in EDMX.
If you have FKs in the DB, make sure the EDMX is aware of them so that the inserts will happen in the correct order (or if using Oracle you can try using deferred constraints instead if you want).

ASP.NET MVC - Foreign Key / Parent-Child and editing records

I've got a number of classes which have a relationship to other classes for properties like Location, Currency etc. Take the following example:
Public Class Transaction
Public Property ID As Integer
Public Property Description As String
Public Property Quantity As Integer
Public Property SaleAmount As Double
Public Overridable Property Currency As Currency
End Class
Public Class Currency
Public Property ID As String
Public Property Description As String
Public Property Symbol As String
Public Property SymbolImage As String
End Class
I add my currencies when I initialise the application for first use. When adding a transaction, I have a drop down box to select the currency.
I have no issues saving the Transaction to the db and the currency ID is saved also.
When I edit the transaction and try to change the currency, I can't get it to save back to the db.
<HttpPost()>
Function Edit(transaction As Transaction) As ActionResult
transaction.Currency = db.Currencies.Find(transaction.Currency.ID)
Debug.Print("Currency: " & transaction.Currency.ID)
If ModelState.IsValid Then
db.Entry(transaction).State = EntityState.Modified
db.SaveChanges()
Return RedirectToAction("Index")
End If
Return View(transaction)
End Function
When I do the debug.print in the post method above, the currency is correctly being reported as the changed currency but the Currency ID on the Transaction record in the DB isn't updated.
I've done some searching and reading and haven't found much/anything.
I did try adding this line to the post method but it still didn't save the changes:
db.Entry(transaction.Currency).State = EntityState.Modified
I'm stumped and would appreciate any help!
So here's the best solution I could find. I'd be interested to hear other ways to achieve the same result. The other methods I've found are much more complicated than this.
Public Class Transaction
Public Property ID As Integer
Public Property Description As String
Public Property Quantity As Integer
Public Property SaleAmount As Double
Public Property Name As String
Public Property CurrencyID() As String
<ForeignKey("CurrencyID")>
Public Overridable Property Currency() As Currency
End Class
I've setup the Edit view with a drop down list containing a list of the currencies and a hidden field to store the CurrencyID. The edit post looks like this:
<HttpPost()>
Function Edit(transaction As Transaction) As ActionResult
If ModelState.IsValid Then
db.Entry(transaction).State = EntityState.Modified
db.SaveChanges()
Return RedirectToAction("Index")
End If
Return View(transaction)
End Function

Resources