EntityFramework 6 in ASP.NET MVC4 Data Annotations - linq

I want to get data between db.TableAs and db.TableBs using the following method:
class TableA.cs:
public class TableA
{
[Key]
public int ID {get;set;}
public int TableBId {get;set;}
public string description{get;set;}
public virtual TableB TableBs{get;set;}
}
class TableB.cs:
public class TableB{
[Key]
public int ID {get;set;}
public int TableAId {get;set;}
public string description{get;set;}
public virtual TableA TableAs{get;set;}
}
I have some functions that need to get TableB's data from TableA and some functions that need to get TableA's data from TableB. By doing this I am getting this error:
Unable to determine the principal end of an association between the types 'TableA' and 'TableB'. The principal end of this association must be explicitly configured using either the relationship fluent API or data annotations.
Can I know how do I get the data without the codes below:
TableB tableB = _tableBmodel.GetSingle(tableA.ID);
public TableB GetSingle(int id)
{
return db.TableBs.Where(e => e.ID == id).FirstOrDefault();
}

Related

Query inner collection using Entity Framework

I have an object Employee
public class Employee
{
public int Id {get;set;}
public ICollection<Address> addresses {get;set;}
}
public class Address
{
public int Id {get;set;}
public string AddressLine1 {get;set;}
public string City {get;set;}
}
Now the Employee is a part of my context.
How do I query the employee object where the address.city is "NY"? I want to traverse to the Address collection from the Employee object in the context.
Thanks
Try with this
MyDBContext.Employee.Where(e => e.Addresses.Any(a => a.city == "NY").ToList();
with this code you will get all Employees, for whom at least one of the address is in New york. If you want that all address of Employee be in New Yowk, then change Any for All.

Linq to Entities: How can i filter in the where clause on fields from a derived type (Table per Type inheritance)?

I am working on a risk monitoring application with a SQL DB in the background. I use EF 4 Database First. There is a "Position" class in the model, which models holdings in various types of assets. A position holds a reference to a "Contract" class. This "Contract" class serves as the base class for various types of financial contracts, such as "Investment".
The classes look as follows:
public class Position
{
public int ContractID {get;set;}
public DateTime PositionDate {get;set;}
public decimal MarketValue {get;set;}
}
public class Contract
{
public int ID {get;set;}
public string Description {get;set;}
public int CurrencyID {get;set;}
public Instrument Instruments {get;set;}
}
public class Investment:Contract
{
public int ID {get;set;}
public int BBGIndustryID {get;set;}
}
When i try to run a query and try to filter on properties from the "Investment" Class, the system throws an StackOverFlowException:
var dataPoint = _context.Positions.Where(c => c.Contract.Instruments != null).Where(c => c.Contract.Instruments.BBGIndustryID == 24).ToList();
How do i need to write the query that i can filter on properties from the derived classes, or do i need to move the properties i need to filter on to move to the base class?

Get The Table Name Of Model In T4 Template

I am using MVC4 ,T4 Scaffolding and EF5.
I Created a model,
namespace wbtest.Models
{
[Table(name: "Pay_Employees_Mst", Schema = "Test")]
public class Employee
{
public int EMPLOYEE_ID { get; set; }
public string EMPLOYEE_CODE { get; set; }
}
}
I need to get the annotation of table name "Pay_Employees_Mst" for db context .Currently getting ModelName Employee.
Please Help.
I got it through,
String entityName1 = (context as System.Data.Entity.Infrastructure.IObjectContextAdapter).ObjectContext
.CreateObjectSet<Employee>()
.EntitySet.Name;

Insert null fails with Model First EF

I'm using a context generated from an EDMX for a mvc3 webapp. I'm getting a NULL insert fails error on an entity
[Serializable]
[DataContract(IsReference = true)]
[EdmEntityType(NamespaceName = "Model", Name = "Thing")]
public class Thing: EntityObject
{
public RolloverEntry();
[DataMember]
[EdmScalarProperty(EntityKeyProperty = true, IsNullable = false)]
public int id { get; set; }
[SoapIgnore]
[EdmRelationshipNavigationProperty("Model", "FK_ThingStep1", "Step1")]
[DataMember]
[XmlIgnore]
public EntityCollection<Step1> Step1 { get; set; }
[SoapIgnore]
[EdmRelationshipNavigationProperty("Model", "FK_ThingStep2", "Step2")]
[XmlIgnore]
[DataMember]
public EntityCollection<Step2> Step2 { get; set; }
public static Thing CreateThing(int id);
}
Data access to other parent-child relationships are working and persisted correctly - I can't seem to find what's wrong with this table tho - any ideas appreciated
Exception Recieved:
{"Cannot insert the value NULL into column 'id', table 'myapp.dbo.Thing'; column does not allow nulls. INSERT fails.\r\nThe statement has been terminated."}
Thanks
I'm guessing you need some sort of hint in your model that the database should generate the ids for the id column. You might want to see if StoreGeneratedPattern is set to Identity for your model property id or something along those lines.

How do I use Linq and Entity Framework to join two jointables?

I have a very normalized database, and I'm trying to join two join tables together.
My goal is to only show documents that the user has permission to. I'm using Entity Framework, and have several foreign keys set up for the following tables:
Relationships (Foreign Keys)
Users ---------------------------------------------
|
UserGroupMembership (UserID, GroupID)
|
|
Groups ----- -------------------------------------------------|
|
|
|---------------------------------------------------------|
|
|
XDocuments XDocumentSecurity (DocumentID, GroupID)
| |
---------------------------------------------
Table Definition
public partial class Users : EntityObject
{
public int UserID {get;set;} //PK
public string UserDisplayName {get;set;}
public DateTime CreateDate {get;set;}
public DateTime LoginDate {get;set;}
}
public partial class Groups : EntityObject
{
public int GroupID {get;set;} //PK
public string GroupDisplayName {get;set;}
public DateTime CreateDate {get;set;}
public DateTime LoginDate {get;set;}
}
public partial class UserGroupMembership: EntityObject // JoinTable
{
public int UserID {get;set;} //PK
public int GroupID {get;set;} //PK
// Not sure if this extra columns below causes an issue
public bool CanView {get;set;}
public bool CanDelete {get;set;}
public bool CanUpdate {get;set;}
public DateTime CreateDate {get;set;}
}
public partial class XDocumentSecurity : EntityObject // JoinTable
{
public int DocumentID {get;set;} //FK
public int GroupID {get;set;} //FK
public DateTime CreateDate {get;set;} // Not sure if this extra column causes an issue
}
public partial class XDocuments : EntityObject
{
public int DocumentID {get;set;} //PK
public string URL {get;set;}
public DateTime CreateDate {get;set;}
}
I've heard of many stories about how Linq to EF alters the SQL query in a way that is sub-optimal for performance.
Here is is the .Union operator sample that seems most applicable to what I'm doing. I could simply get a list of groups the current user is a member of and issue a modified version of this query:
public void Linq50()
{
int[] numbersA = { 0, 2, 4, 5, 6, 8, 9 };
int[] numbersB = { 1, 3, 5, 7, 8 };
var commonNumbers = numbersA.Intersect(numbersB);
Console.WriteLine("Common numbers shared by both arrays:");
foreach (var n in commonNumbers)
{
Console.WriteLine(n);
}
}
Question
How do I view the SQL query that EF generates?
What is a better way to approach this problem (if any)
You can also view the SQL generated by EF 4.1 using either
SQL Profiler
LINQPad
Although, at this time, you need to use the LINQPad beta for EF 4.1.
Regarding your second question, I believe your query would translate fine. Using LINQPad to check the SQL, the following query
var a1 = Addresses.Where(a => a.City.ToUpper().EndsWith("L")).Select(a => a.AddressID);
var a2 = Addresses.Where(a => a.City.ToUpper().StartsWith("B")).Select(a => a.AddressID);
var x1 = a1.Intersect(a2);
translates to
SELECT
[Intersect1].[AddressID] AS [C1]
FROM (SELECT
[Extent1].[AddressID] AS [AddressID]
FROM [Person].[Address] AS [Extent1]
WHERE UPPER([Extent1].[City]) LIKE N'%L'
INTERSECT
SELECT
[Extent2].[AddressID] AS [AddressID]
FROM [Person].[Address] AS [Extent2]
WHERE UPPER([Extent2].[City]) LIKE N'B%') AS [Intersect1]
I think #Slauma's recommendation to use navigation proeprties is the way to go if your model supports it.
Still, get LINQPad - you won't regret it :)
If you have navigation properties for all your keys and foreign keys an alternative query without an Intersect would be:
var query = context.XDocuments
.Where(d => d.Groups.Any(g => g.Users.Any(u => u.UserID == givenUserId)));
("Filter all documents which are in at least one group which has at least one user with the key = givenUserId")
I don't know if this will be better with respect to performance.
In EF 4.1 you can inspect the generated SQL simply by:
var sql = query.ToString();
Edit
My understanding how your model would look is the following:
Three entities with corresponding tables:
public class User
{
public int UserID { get; set; }
public ICollection<Group> Groups { get; set; }
}
public class Group
{
public int GroupID { get; set; }
public ICollection<User> Users { get; set; }
public ICollection<XDocument> Documents { get; set; }
}
public class XDocument
{
public int DocumentID { get; set; }
public ICollection<Group> Groups { get; set; }
}
And between User and Group a many-to-many relationship and between Group and XDocument as well:
modelBuilder.Entity<User>()
.HasMany(u => u.Groups)
.WithMany(g => g.Users)
.Map(c =>
{
c.MapLeftKey("UserID");
c.MapRightKey("GroupID");
c.ToTable("UserGroupMembership"); // join table name, no entity
});
modelBuilder.Entity<XDocument>()
.HasMany(d => d.Groups)
.WithMany(g => g.Documents)
.Map(c =>
{
c.MapLeftKey("DocumentID");
c.MapRightKey("GroupID");
c.ToTable("XDocumentSecurity"); // join table name, no entity
});
In this model and mapping the query described above should be possible. There is no need to access the join tables directly (and you can't actually access them via LINQ to Entities, EF manages those tables internally).

Resources