Entity properties can be split across different tables, meaning that a single Entity can have it's columns mapped to different tables. How does one then, in code, retrieve the info on the particular table an entity property is mapped to.
foreach(PropertyInfo pi in typeof(DbContext).GetProperties())
{
if(pi.PropertyType.IsGenericType && pi.PropertyType.Name.Contains("DbSet"))
{
var t = pi.PropertyType.GetGenericArguments().FirstOrDefault();
var tables = t.GetCustomAttributes(true).OfType<TableAttribute>();
foreach (var entityProperty in t.GetProperties())
{
if (entityProperty.GetCustomAttributes(true).OfType<RequiredAttribute>().Any<RequiredAttribute>())
{
var fieldname = entity.Name;
//I need to match this column with the table it belongs to here
}
}
}
}
So far, I have the code below to get at the entity property, from the object itself, how do I determine the particular table the current property is mapped to, in my database? Thanks in advance.
Consider using the OR/M for the actual generation of the SQL you actually need.
var dbContext = new DbContext();
var objectContext = ((IObjectContextAdapter)dbContext).ObjectContext;
var set = objectContext.Set<Foo>();
var query = from x in set
where {stuff}
select new { x.Bar, x.Baz ...};
var objectQuery = (ObjectQuery)query;
var command = objectQuery.CommandText;
var parameters = objectQuery.Parameters;
Related
I have entities stored in one table that look like (truncated here):
public class Record : TableEntity
{
public double Version;
public string User;
}
Basically, I want to retrieve all the RowKeys and only the Version column of the entire table (i.e. the entire first 2 columns). There is only one PartitionKey since there aren't too many entries. How can I programmatically retrieve these columns? I'm aware of query projection and have seen the example on the Azure site, but I don't know how to extend it for my purpose here.
Any help would be appreciated!
Please try the following code. Essentially you would need to specify the columns you wish to fetch in SelectColumns property of your query. I have not specified any filter criteria because you mentioned that the table doesn't contain that many entities.
static void QueryProjectionExample()
{
var cred = CloudStorageAccount.DevelopmentStorageAccount;
var client = cred.CreateCloudTableClient();
var table = client.GetTableReference("TableName");
var query = new TableQuery<DynamicTableEntity>()
{
SelectColumns = new List<string>()
{
"RowKey", "Version"
}
};
var queryOutput = table.ExecuteQuerySegmented<DynamicTableEntity>(query, null);
var results = queryOutput.Results;
foreach (var entity in results)
{
Console.WriteLine("RowKey = " + entity.RowKey + "; Version = " + entity.Properties["Version"].StringValue);
}
}
I have a database with owner and vehicle tables with a one-to-many relationship. I want to get all vehicle details and map each owner to each vehicle but I must map the query to a BDO. Not sure on the LINQ syntax but I have the code below.
using (var databaseContext = new DBConnection()) {
var vehicles = (from Vehicle in databaseContext.Vehicles
select Vehicle);
return vehicles.Select(x => new VehicleBDO() {
Id = x.Id,
// ... more simple data types
Owner = new OwnerBDO(
x.Owner.Id,
x.Owner.Name)
}).ToList();
}
Creating a new ownerBDO as shown is giving me a MethodNotSupportedException with details:
Only parameterless constructors and initializers are supported in LINQ
to Entities
I'm used to Java and new to LINQ so have no idea how to do it properly, any help would be much appreciated.
It wants you to do something like this:
Owner = new OwnerBDO() { Id = x.Owner.Id, name = x.Owner.Name},
(I don't know the property names for OwnerBDO so I guessed.)
So, in a desperate attempt to wrangle EntityFramework into being usable. I am here..
private MyEntity Update(MyEntity orig)
{
//need a fresh copy so we can attach without adding timestamps
//to every table....
MyEntity ent;
using (var db = new DataContext())
{
ent = db.MyEntities.Single(x => x.Id == orig.Id);
}
//fill a new one with the values of the one we want to save
var cpy = new Payment()
{
//pk
ID = orig.ID,
//foerign key
MethodId = orig.MethodId,
//other fields
Information = orig.Information,
Amount = orig.Amount,
Approved = orig.Approved,
AwardedPoints = orig.AwardedPoints,
DateReceived = orig.DateReceived
};
//attach it
_ctx.MyEntities.Attach(cpy, ent);
//submit the changes
_ctx.SubmitChanges();
}
_ctx is an instance variable for the repository this method is in.
The problem is that when I call SubmitChanges, the value of MethodId in the newly attached copy is sent to the server as 0, when it is in fact not zero if I print it out after the attach but before the submit. I am almost certain that is related to the fact that the field is a foreign key, but I still do not see why Linq would arbitrarily set it to zero when it has a valid value that meets the requirements of the constraint on the foreign key.
What am I missing here?
You should probably set Method = orig.Method, but I can't see your dbml, of course.
I think you need to attach the foreign key reference
var cpy = new Payment()
{
//pk
ID = orig.ID,
//other fields
Information = orig.Information,
Amount = orig.Amount,
Approved = orig.Approved,
AwardedPoints = orig.AwardedPoints,
DateReceived = orig.DateReceived
};
//create stub entity for the Method and Add it.
var method = new Method{MethodId=orig.MethodId)
_ctx.AttachTo("Methods", method);
cpy.Methods.Add(method);
//attach it
_ctx.MyEntities.Attach(cpy, o);
//submit the changes
_ctx.SubmitChanges();
When I do a lunq query on an EF model, does it not get child entities we well? I have a Transaction table, which has link to a Payee, and a transaction type entity. Also, each transaction has a list of transaction lines...
But the code bellow - all the child objects seen to be NULL, yet the data in the actual entity (Date) seems OK. But in the line: t.account.account_id; .... 'account' is NULL.
public static List<AccountTransactionDto> GetTransaction()
{
var trans = (from t in Db.account_transaction
select t).ToList();
List<AccountTransactionDto> al = new List<AccountTransactionDto>();
foreach(var t in trans)
{
AccountTransactionDto a = new AccountTransactionDto();
a.AccountId = t.account.account_id;
a.AccountTransactionId = t.account_transaction_id;
a.PayeeId = t.payee.payee_id;
a.TransactionDate = t.transaction_date;
a.TransactionTypeId = t.z_transaction_type.transaction_type_id;
foreach(var tl in t.account_transaction_line)
{
AccountTransactionLineDto l = new AccountTransactionLineDto();
l.AccountTransactionLineId = tl.account_transaction_line_id;
l.Amount = tl.amount;
l.BudgetId = tl.budget.budget_id;
l.CostCenterId = tl.cost_centre.cost_centre_id;
l.SubCategoryId = tl.sub_category.sub_category_id;
a.AccountTransactionLine.Add(l);
}
al.Add(a);
}
return al;
}
You have two options. You can enable the Lazy Loading via:
Db.ContextOptions.LazyLoadingEnabled = true;
Or if you change the query line to this (exact syntax may not be correct for Include):
var trans = (from t in Db.account_transaction
select t).Include("account_transaction.account_transaction_line");
Then it should pull back the child records with the parent record in a single result set. But this has performance penalties if there is a great amount of data.
Lazy loading needs to be enabled on your data context.
Db.ContextOptions.LazyLoadingEnabled = true;
or you need to explicitly tell EF to load the association. i.e.
var trans = (from t in Db.account_transaction.Include('account').Include('payee') select t).ToList();
I have a many to many relationship between Contractors and SafetyCouncils. They are joined by a bridge table ContractorsSafetyCouncils which consists of ContractorId and SafetyCouncilId. These 2 columns form a composite key. This relationship is mapped correctly in EF4. The Contractor entity has the property:
public virtual ICollection<SafetyCouncil> SafetyCouncils
{
get;
set;
}
And the SafetyCouncil entity has the property:
public virtual ICollection<Contractor> Contractors
{
get;
set;
}
When accessing these properties via lazy loading from a single Contractor or SafetyCouncil entity, they work exactly as expected. But when accessing this relationship in a query:
from c in ContractorRepository.All()
where c.PQFs.Count() > 0
let psmAudits = c.PQFs.SelectMany(pqf => pqf.Audits)
let psmAudit = psmAudits.FirstOrDefault(audit => audit.CompletedDate == psmAudits.Max(a => a.CompletedDate))
let scsAudits = c.PQFs.SelectMany(pqf => pqf.SCSAudits)
let scsAudit = scsAudits.FirstOrDefault(audit => audit.CompletedDate == scsAudits.Max(a => a.CompletedDate))
select new MasterListItem()
{
AdministratorNotes = c.AdminFlags.Where(f => f.IsActive && f.ForPQF).Select(f => f.Text),
CanViewInfo = false,
ContractorName = c.ContractorName,
ContractorId = c.Id,
ContractorTaxId = c.TaxId,
SafetyCouncilIds = c.SafetyCouncils.Select(sc => sc.Id),
PQFSubmitted = c.PQFs.Max(p => p.PQFInfo.SubmittedDate.Value),
PSMAuditId = psmAudit.Id,
PSMAuditComplete = psmAudit.CompletedDate,
PSMAuditStatus = psmAudit.Status.Description,
SCSAuditId = scsAudit.Id,
SCSAuditComplete = scsAudit.CompletedDate
};
The problem occurs with:
SafetyCouncilIds = c.SafetyCouncils.Select(sc => sc.Id),
For every record the SafetyCouncilIds collection has 0 members, when based on the data in the database every record should have at least 1 SafetyCouncilId associated with it.
If I run the same query, but project into an anonymous type instead of the MasterListItem type, it works correctly. Why can't I project this query into my custom type?
Update:
My MasterListItem POCO contained the following properties:
public string SafetyCouncilIdsString
{
get;
set;
}
public IEnumerable<int> SafetyCouncilIds
{
set
{
StringBuilder sb = new StringBuilder(",");
foreach (var id in value)
{
sb.Append(id);
sb.Append(",");
}
this.SafetyCouncilIdsString = sb.ToString();
}
}
The SafetyCouncilIds property was the cause of the problem. I changed this to an automatic property and built the string elsewhere and projecting onto the POCO worked like a charm.
public IEnumerable<int> SafetyCouncilIds
{
set
{
StringBuilder sb = new StringBuilder(",");
foreach (var id in value)
{
sb = sb.Append(id).Append(","); // <-- try this
// *or sb = sb.AppendFormat("{0},", id);*
}
this.SafetyCouncilIdsString = sb.ToString();
}
}
I have two suggestions:
Try to isolate the the problem by removing any extra parts of the query.
Compare the two sql queries generated and find the differences.
Unfortunately, without access to your code or schema, I can't provide a better answer.
The SafetyCouncilIds property was the cause of the problem. I changed this to an automatic property and built the string elsewhere and projecting onto the POCO worked like a charm.