EF 4.1 Code First adding to a foreign key collection - entity-framework-ctp5

If I have an entity with a collection property for another entity. What is the best way to add a new entity and it's related entities? The problem I have is that the collection is initially null.
var form = new Form()
{
Name = "TestForm"
};
ctx.Forms.Add(form);
var formField = new FormField()
{
Name = "TestField"
};
form.FormFields.Add(formField);
ctx.SaveChanges();
The form.FormFields property above is null so I get an exception. I know I could set the relationship in the other direction but I haven't defined a Form property on FormFields (and I don't really want to).
So what is the cleanest solution to for this?

The simplest solution is to initialize the collection like this:
var form = new Form() {
Name = "TestForm"
};
ctx.Forms.Add(form);
var formField = new FormField() {
Name = "TestField"
};
if(form.FormFields == null)
form.FormFields = new List<FormField>();
form.FormFields.Add(formField);
ctx.SaveChanges();

Related

Dynamically ignore attributes when saving items with .NET AWS SDK Object Persistence Model

Is it possible to dynamically ignore some properties when saving items with the .NET Object Persistence Model?
I don't want to decorate my class properties with DynamoDBIgnore because sometimes I do want to save the changes being made in those.
I have tried to set IgnoreNullValues to true however this did not work when saving items with a batch.
Code is as follows:
using (var context = new DynamoDBContext(awsClient, _dynamoDbContextConfig))
{
var batch = context.CreateBatchWrite<T>(
new DynamoDBOperationConfig {SkipVersionCheck = true, IgnoreNullValues = true});
batch.AddPutItems(items);
await context.ExecuteBatchWriteAsync(new BatchWrite[] {batch});
}
Shall I use the lower-level API for achieving this?
The lower level API (exposed through IAmazonDynamoDB / AmazonDynamoDbClient) is the only way I have found till now of updating individual properties of an existing DynamoDB document.
An example of this would be :
var updateItemRequest = new UpdateItemRequest
{
TableName = "search_log_table",
Key = new Dictionary<string, AttributeValue>
{
{"PK", new AttributeValue("pk_value")},
{"SK", new AttributeValue("sk_value")}
},
UpdateExpression = $"SET SearchCount = if_not_exists(SearchCount, :start) + :inc",
ExpressionAttributeValues = new Dictionary<string, AttributeValue>
{
{":start", new AttributeValue {N = "0"}},
{":inc", new AttributeValue {N = "1"}}
},
ReturnValues = "UPDATED_NEW"
};
// _client is an instance of IAmazonDynamoDB
return _client.UpdateItemAsync(updateItemRequest);
This inserts a new record with PK = "pk_value", SK = "sk_value" if one does not exist.
The statement UpdateExpression = $"SET SearchCount = if_not_exists(SearchCount, :start) + :inc sets the SearchCount to 1 the first time, and increments the property by 1 on every subsequent invocation

Entity Framework 6 .add() with variable table and column name

I am able to get a somewhat dynamic Entity Framework search result with the following simplified example, which pulls a single result from the DB or Cache:
string strTableName = "TableName2"
string strColumnName = "MyColumnName"
int intPrimaryKey = 1
Type returnType;
returnType = typeof(TableName1);
string queryResults = null;
switch (strTableName)
{
case "TableName2":
returnType = typeof(TableName2);
break;
}
var refColumnName = returnType.GetProperty(strColumnName );
var query = mydbEntity.Set(returnType).Find(intPrimaryKey );
var queryResults = refColumnName.GetValue(query).ToString();
This can also be adapted for Updating a record:
DataQuery.LeadsEntity.Entry(query).Property(strColumnName ).CurrentValue = "Whatever";
DataQuery.LeadsEntity.SaveChanges();
Is there an equivalent for way for .set(returnType).Add()? I'm not sure if there is a way to do this type of thinking using variable table and column names:
DataQuery.LeadsEntity.Set(returnType).Add(new returnType { PrimayKeyName = 1, refColumnName = "Something" });
If you don't know a priori what's the name of the primary key property, it could be a little painful to get it from the type.
This is the way I found more reliable to retrieve the primary key from the entity type:
private string[] GetKeyNames(DbContext context, Type entityType)
{
ObjectContext objectContext = ((IObjectContextAdapter)context).ObjectContext;
//create method CreateObjectSet with the generic parameter of the base-type
MethodInfo method = typeof(ObjectContext).GetMethod("CreateObjectSet", Type.EmptyTypes)
.MakeGenericMethod(entityType);
dynamic objectSet = method.Invoke(objectContext, null);
IEnumerable<dynamic> keyMembers = objectSet.EntitySet.ElementType.KeyMembers;
string[] keyNames = keyMembers.Select(k => (string)k.Name).ToArray();
_keyNamesCache[entityType] = keyNames;
return keyNames;
}
But assuming your primary keys are always a single property, you could use reflection to create the entity object and set its properties like this:
private void CreateEntity(Type entityType, object pkValue, Dictionary<string, object> Columns)
{
// Create the new entity
var entity = Activator.CreateInstance(entityType);
// Get the primary key property name
var pkName = GetKeyNames(context, entityType).First();
// Set Pk value
entityType.GetProperty(pkName).SetValue(entity, pkValue);
// Set other column(s)
foreach (var col in Columns)
{
entityType.GetProperty(col.Key).SetValue(entity, col.Value);
}
// Add the entity to the DbSet
using (var context = new YourContext())
{
context.Set(entityType).Add(entity);
}
}

DeExpress MVC 17.1 How populate TokenBox from a database

I want populate a TokenBox from a database using the property tokenBoxSettings.Properties.DataSource
TokenBoxView.cshtml
groupSettings.Items.Add(
formLayoutSettings.Items.Add(i =>
{
i.FieldName = "email";
i.Caption = "Email";
i.NestedExtensionType = FormLayoutNestedExtensionItemType.TokenBox;
TokenBoxSettings tokenBoxSettings = (TokenBoxSettings) i.NestedExtensionSettings;
tokenBoxSettings.Width = 350;
//data binding
tokenBoxSettings.Properties.DataSource = mainController.GetMails();
tokenBoxSettings.Properties.TextField = "email_empresarial";
tokenBoxSettings.Properties.ValueField = "email_empresarial";
tokenBoxSettings.Properties.IncrementalFilteringMode = IncrementalFilteringMode.Contains;
tokenBoxSettings.Properties.ValueSeparator = ';';
})
);
TokenBoxController.cs
//mainController
//I created a dictionary based on the result of select
public Dictionary<string, string> GetMails()
{
var email = db.usuario.ToList().Select(e => new { e.email_empresarial });
var emails = new Dictionary<string, string>();
foreach (var mail in email)
{
correos.Add(mail.ToString(), mail.ToString());
}
return emails;
}
But it shows me the "object explicitly", I only need the value, for example kenneth or manuel
tokenBox list
What am I doing wrong? or with what other approach I can do?
You are specifying same email_empresarial field name for both tokenBoxSettings.Properties.TextField and tokenBoxSettings.Properties.ValueField.
Since you are binding your TokenBox to Dictionary, try changing settings for TextField and ValueField to reference Dictionary Key and Value, like this:
tokenBoxSettings.Properties.TextField = "Value";
tokenBoxSettings.Properties.ValueField = "Key";
Also, in your GetMail() method you have declared the var emails but in the loop you are adding items to the undeclared correos variable. Are you sure you don't have a bug here?
Another note, in the Dictionary returned by GetMails() you populate both dictionary keys and values with the same value of mail.ToString(). Are you sure you really need to use Dictionary to bind your TokenBox? If keys and values are equal you may try going with plain List<string>.

Question about using Anonymous List Types

private List<T> GetFieldList()
{
var Fields = new { DisplayName = "MCP", FieldName = "t.MCP", FieldType = 1 };
var FieldList = (new[] { Fields }).ToList();
return FieldList;
}
Should I be able to do something like this?
If I understand correctly your tag "asp.net" this construction will be used as part of data binding.
Just use non generic :
private IList GetFieldList()
{
var Fields = new { DisplayName = "MCP", FieldName = "t.MCP", FieldType = 1 };
IList FieldList = (new[] { Fields }).ToList();
return FieldList;
}
It would be nice handled by all data-bound controls.
I just realized I don't need to use an anonymous list as I know the structure of the data I'm expecting, so I'll just create a small class for it.

Entity Framework Updating with Related Entity

I'm using the EF to try to update an entity with ASP.NET. I'm creating an entity, setting it's properties then passing it back to the EF on a separate layer with the ID so the change can be applied. I'm doing this because I only store the ID of the entity when it's been bound to the UI controls.
Everything works for standard properties, but I can't update the Category.ID of a Product (a related entity). I've tried EntityKey, EntityReference and a few other but the category ID isn't saved. This is what I have:
Product product = new Product();
product.CategoryReference.EntityKey = new EntityKey("ShopEntities.Categories", "CategoryID", categoryId);
product.Name = txtName.Text.Trim();
... other properties
StockControlDAL.EditProduct(productId, product);
public static void EditProduct(int productId, Product product) {
using(var context = new ShopEntities()) {
var key = new EntityKey("ShopEntities.Products", "ProductID", productId);
context.Attach(new Product() { ProductID = productId, EntityKey = key });
context.AcceptAllChanges();
product.EntityKey = key;
product.ProductID = productId;
context.ApplyPropertyChanges("ShopEntities.Products", product);
context.SaveChanges();
}
}
I really want to use the EF but I seem to be having a few problems with using it with ASP.NET.
The reason this fails is two fold.
In order to update a Reference (i.e. Product.Category) you have to have the original reference value in the context too.
ApplyPropertyChanges(...) only applies to regular / scalar properties of the Entity, the reference is left unchanged
So I would do something like this (Note this code makes heavy use of a trick called stub entities to avoid mucking around with EntityKeys)
Product product = new Product();
// Use a stub because it is much easier.
product.Category = new Category {CategoryID = selectedCategoryID};
product.Name = txtName.Text.Trim();
... other properties
StockControlDAL.EditProduct(productId, originalCategoryID);
public static void EditProduct(Product product, int originalCategoryID ) {
using(var context = new ShopEntities())
{
// Attach a stub entity (and stub related entity)
var databaseProduct = new Product {
ProductID = product.ProductID,
Category = new Category {CategoryID = originalCategoryID}
};
context.AttachTo("Products", databaseProduct);
// Okay everything is now in the original state
// NOTE: No need to call AcceptAllChanges() etc, because
// Attach puts things into ObjectContext in the unchanged state
// Copy the scalar properties across from updated product
// into databaseProduct in the ObjectContext
context.ApplyPropertyChanges("ShopEntities.Products", product);
// Need to attach the updated Category and modify the
// databaseProduct.Category but only if the Category has changed.
// Again using a stub.
if (databaseProduct.Category.CategoryID != product.Category.CategoryID)
{
var newlySelectedCategory =
new Category {
CategoryID = product.Category.CategoryID
};
context.AttachTo("Categories", newlySelectedCategory)
databaseProduct.Category = newlySelectedCategory;
}
context.SaveChanges();
}
}
This will do the job, assuming no typos etc.
This is accepted answer to this question Strongly-Typed ASP.NET MVC with Entity Framework
context.AttachTo(product.GetType().Name, product);
ObjectStateManager stateMgr = context.ObjectStateManager;
ObjectStateEntry stateEntry = stateMgr.GetObjectStateEntry(model);
stateEntry.SetModified();
context.SaveChanges();
Have you tried out that?
[Updated, code on top does not work]
This is small extension property I used so next code block is easier to understand:
public partial class Product
{
public int? CategoryID
{
set
{
CategoryReference.EntityKey = new EntityKey("ShopEntities.Categories", "CategoryID", value);
}
get
{
if (CategoryReference.EntityKey == null)
return null;
if (CategoryReference.EntityKey.EntityKeyValues.Count() > 0)
return (int)CategoryReference.EntityKey.EntityKeyValues[0].Value;
else
return null;
}
}
}
and that worked for me (this time for sure):
System.Data.EntityKey key = new System.Data.EntityKey("ShopEntities.Products", "ProductID", productId);
object originalItem;
product.EntityKey = key;
if (context.TryGetObjectByKey(key, out originalItem))
{
if (originalItem is EntityObject &&
((EntityObject)originalItem).EntityState != System.Data.EntityState.Added)
{
Product origProduct = originalItem as Product;
origProduct.CategoryID == product.CategoryID;//set foreign key again to change the relationship status
context.ApplyPropertyChanges(
key.EntitySetName, product);
}
}context.SaveChanges();
For sure it's looks hacky. I think that the reason is because the EF relationships have status as entities (modified, added, deleted) and based on that status EF changes the value of foreign keys or deletes row if many to many relationship is in case. For some reason (don't know why) the relationship status is not changed the same as property status. That is why I had to set the CategoryReference.EntityKey on originalItem in order to change the status of the relationship.

Resources