EF: Partial class - acces to the adapter? - entity-framework

let's say that I have a table TabA
namespace MyProject.Models.Database //<-- the same namespace as the EF's dbmx file
{
public partial class TabA
{
public void Foo()
{
//
}
}
}
Inside the Foo method, I need to perform some operations on the other table which isn't asosiated with the TabA In the other words, I need to access to the Entity Framework adapter inside that method. Is it possible ?
Edit
the answer is here https://stackoverflow.com/a/11135157/106616

If I understand the problem correctly, I assume you have your reasons for wanting to work on another entity from the TabA entity. If this is true, I can see two ways of doing this.
A) If you want your changes to be applied at the same time as other potential changes to the TabA Entity, then you can always pass in the context as a parameter:
namespace MyProject.Models.Database //<-- the same namespace as the EF's dbmx file
{
public partial class TabA
{
public void Foo(YourDbContext context)
{
var otherTableQuery = from x in context.SecondTable
where ...
select x;
foreach (var item in otherTableQuery)
{
item.Column1 = "A certain value";
}
}
}
}
Your calling method might look like:
public void DoChangesToTabA()
{
using ( YourDbContext context = new YourDbContext())
{
var tabAquery = from x in context.TabA
where ...
select x;
foreach( var item in tabAQuery)
{
item.LastModified = DateTime.Now;
if(???)
{
}
}
}
}
Now your changes will be applied the next time you call context.SaveChanges() from the calling method.

Related

MapStruct: How to update a bean reference instead properties values

Folks,
I have the following situation with MapStruct: I want to always update a field with a new instance instead of setting values in a pre-existing instance.
Example:
class A {
     B fieldB;
}
class B {
     String fieldString;
}
class ADTO {
     BDTO fieldB;
}
class BDTO {
     String fieldString;
}
I have the following mapping with MapStruct:
void copy(ADTO aDTO, #MappingTarget A a);
The result generated is similar to:
if (aDTO.getFieldB()!= null) {
if (a.getFieldB() == null) {
a.setFieldB(new B());
}
bDTOToB(aDTO.getFieldB(), a.getFieldB());
} else {
a.setFieldB(null);
}
What I would like to generate is the following:
if (aDTO.getFieldB()!= null) {
a.setFieldB(new B()); // ALWAYS create a new B instance
bDTOToB(aDTO.getFieldB(), a.getFieldB());
} else {
a.setFieldB(null);
}
I add that I need the 2 behaviors: for some fields the current behavior suits me, that is, set the values in an existing instance. For other fields, I need this change in behavior as I mentioned before (a.setFieldB(newB())).
Is it possible to do that? What better strategy?
The only way this is possible is like this:
#BeforeMapping
default void init( #MappingTarget A a ) {
a.setFieldB( new B() );
}
void copy(ADTO aDTO, #MappingTarget A a);
The #BeforeMapping will set your field prior to check. It will however not ommit the (now obsolete) null check on the target in the generated code.
There's no way to control the target check in MapStruct. The NullValuePropertyMappingStrategy defines how a null source should be handled in the target.

EF: How to enclose context object in a using statement?

Let's say I have the following classes Customer.cs, a context OfficeContext.cs, and a repository OfficeRepository.cs. Knowing that the context use a connection object, so it's advised to enclose it in a using statement:
public List<Customer> GetAllCustomersWithOrders()
{
using(var oContext = new OfficeContext())
{
//Code here....
}
}
My question is what if I want to re-use some of the code already in the repository? For instance, what if I want to display all the customers that ordered products but didn't receive them yet, do I need to duplicate the code?
public List<Customer> GetCustomersNotReceiveProducts()
{
using(var oContext = new OfficeContext())
{
//Re-use GetAllCustomersWithOrders() here???...
}
}
But as you can see, each time access a method, I also open instantiate a new context object. Is there any way to deal with that?
What I do is have my repositories implement IDisposable.
Then have two constructors (one default) that instaniates a new context that holds it as a class level variable. And another constructor that takes a context and uses that internally.
The on the dispose of the class the context is disposed (if the current repository instatiated it).
This removes the context out of the method level and moves it to the class level. My functions keep everything in IQueryable so one function can call another function and perform additional refinements before the database it hit.
Exmaple:
public class MemberRepository : IDisposable
{
OfficeContext db;
bool isExternalDb = false;
public MemberRepository()
{
db = new OfficeContext();
isExternalDb = false;
}
public MemberRepository(OfficeContext db)
{
this.db = db;
isExternalDb = true;
}
public IQueryable<Member> GetAllMembers()
{
var members= db.Members
return members;
}
public IQueryable<Member> GetActiveMembers()
{
var members = GetAllMembers();
var activeMembers = members.Where(m => m.isActive == true);
return activeMembers;
}
public void Dispose()
{
if (isExternalDb == false)
{
db.Dispose();
}
}
}
Then where I use the repository, I do a using at that level:
using(var memberRepository = new MemberRepository())
{
var members = memberRepository.GetActiveMembers();
}

Entity Framework as DAL how to implement Update and Delete correctly

I'm writing a DAL class using EF4.0, I've read
http://www.codeproject.com/Articles/43367/ADO-NET-Entity-Framework-as-Data-Access-Layer
and
http://msdn.microsoft.com/en-us/magazine/cc700340.aspx
But when I test their code, I meet some problem with the Update and Delete method.
The DAL class all code is below:
public class FriendlinkDA : IDisposable
{
private EdiBlogEntities context;
public FriendlinkDA()
{
context = new EdiBlogEntities();
}
public void Dispose()
{
context.Dispose();
}
public FriendLink GetFriendLink(Guid id)
{
return context.FriendLink.FirstOrDefault(f => f.Id == id);
}
public void Update(FriendLink model)
{
// Way 1: (throw exception)
//context.Attach(model);
//model.SetAllModified(context);
//context.SaveChanges();
// Way 2:
EntityKey key;
object originalItem;
key = context.CreateEntityKey("FriendLink", model);
if (context.TryGetObjectByKey(key, out originalItem))
{
context.ApplyCurrentValues(key.EntitySetName, model);
//context.ApplyPropertyChanges(key.EntitySetName, model);
}
context.SaveChanges();
}
public void Delete(FriendLink model)
{
// Way 1:
context.Attach(model);
context.DeleteObject(model);
context.SaveChanges();
// Way 2:
//var item = context.FriendLink.FirstOrDefault(f => f.Id == model.Id);
//context.DeleteObject(item);
//context.SaveChanges();
}
}
The extension method is:
public static void SetAllModified<T>(this T entity, ObjectContext context) where T : IEntityWithKey
{
var stateEntry = context.ObjectStateManager.GetObjectStateEntry(entity.EntityKey);
var propertyNameList = stateEntry.CurrentValues.DataRecordInfo.FieldMetadata.Select
(pn => pn.FieldType.Name);
foreach (var propName in propertyNameList)
stateEntry.SetModifiedProperty(propName);
}
In the application, I am use the DAL like this:
// Delete
using (var optFriendlink = new FriendlinkDA())
{
var test = optFriendlink.GetFriendLink(new Guid("81F58198-D396-41DE-A240-FC306C7343E8"));
optFriendlink.Delete(test);
}
// Update
using (var optFriendlink = new FriendlinkDA())
{
var testLink = optFriendlink.GetFriendLink(new Guid("62FD0ACF-40C3-4BAD-B438-38BB540A6080"));
testLink.Title = "ABC";
optFriendlink.Update(testLink);
}
Question 1:
In Delete(), both way 1 and way 2 can work. Which one is better?
Question 2:
In Update(), way 1 give me an exception: The object cannot be attached because it is already in the object context. An object can only be reattached when it is in an unchanged state.
on this statment: context.Attach(model);
but way 2 is fine.
why is this happening? I also attach the model in Delete(), why Delete() is working fine? how I can write the update correctly?
The exception says it all:
An object can only be reattached when it is in an unchanged state.
You change the object in the code snippet under // Update, so that's why it cannot be re-attached.
As to which method is better. Normally you would get an object from a context, dispose of the context, do something with the object and then use a new context to save the object. In that case using Attach is much more comfortable then getting an object by Id first.

autofac: IEnumerable<Lazy<IFoo, IFooMetaData>> --> Lazy.Value(with runtime param)?

Using Autofac, I have multiple IFoo components that take a run-time parameter in the constructor. I'm using some Metadata from the types along with the run-time parameter to construct and manage running instances.
interface IFoo
{
int RunTimeId { get; }
}
[FooMeta("ShaqFoo")]
class Foo1 : IFoo
{
public Foo1 (int runtTimeId)
{
...
}
[FooMeta("KungFoo")]
class Foo2 : IFoo
{
public Foo2 (int runtTimeId)
{
...
}
Module/Registration something like:
builder.Register<Func<int, Foo1>>(c =>
{
var cc = c.Resolve<IComponentContext>();
return id => cc.Resolve<Foo1>(TypedParameter.From<int>(id));
})
.As<Func<int, IFoo>>()
.WithMetadata<IFooMetaData>(m => m.For(sm => sm.FooType, typeof(Foo1)));
builder.Register<Func<int, Foo2>>(c =>
{
var cc = c.Resolve<IComponentContext>();
return id => cc.Resolve<Foo2>(TypedParameter.From<int>(id));
})
.As<Func<int, IFoo>>()
.WithMetadata<IFooMetaData>(m => m.For(sm => sm.FooType, typeof(Foo2)));
And a component that creates new Foos with the run-time parameters and metadata. I need to be create ALL IFoos for a given run-time parameter, and need to check for existing instances (essentially using Metadata + RunTimeId as a key) before creating.
public class FooActivator
{
public FooActivator(IEnumerable<Lazy<Func<int, IFoo>, IFooMetaData>> fooFactories)
{
m_FooFactories = fooFactories;
}
private void HandleNewRunTimeIdEvent(int id)
{
CreateFoosForNewId(id);
}
private void CreateFoosForNewId(int id)
{
foreach (var fooFactory in m_FooFactories)
{
if (!FooWithThisMetadataAndIdExists(fooFactory.Metadata.FooType, id))
{
var newFoo = fooFactory.Value(id);
}
}
}
}
Obviously, I can enumerate all of the IFoos and check metadata using the Lazy Enumeration, but can't pass in the run-time parameter to Lazy.Value. Seems like I need to pass in an Enumerable of Func<>s somehow, but can't figure out how to attach the metadata. Or maybe I need an entirely different approach?
Just getting my head wrapped around autofac, and hoping there's a clean way to accomplish this. I could settle for just using the concrete Foo type (instead of metadata) if there's a simple way to enumerate all of them (without creating them), and use the type + run-time Id as my key instead.
Updated the code with a working solution. Figured out how to register Factories properly with metadata. Seems to work.

Using DataAnnotations (DisplayColumn) in WCF RIA Services

I have created an entity framework 4.0 (DB-First) model, added my partial classes and used DataAnnotations on them to have a perfect UI on the client.
I have some relations between my tables and used DisplayColumn on top my classes. e.g. I have a User class that has [DataColumn("UserName")] attribute on top of the class. And a Message class which has "public User Sender" which has [Include] attribute on top of the property.
Also, I have used .Include("User") in my DomainService to load the User who's related to a message.
But in my datagrid, I see User : (UserID) (UserID=Key property of User entity) instead of UserName that I have specified. I looked in the generated code in my SL project and it correctly decorated my User class with DisplayColumn attribute. But still, I cannot see UserName in my grid.
Any help would be greatly appreciated.
Update: Here's my question in code:
As I have mentioned, Owner, UserName, MessageId, UserId have been defined in my auto-generated model. UserMeta class has nothing special.
[MetadataType(typeof(MessageMeta))]
public partial class Message
{
}
public class MessageMeta
{
[Include()]
[Display(Name = "Belongs to", Order = 4)]
[Association("Message_User","MessageId","UserId",IsForeignKey = true)]
public virtual User Owner { get; set; }
}
[MetadataType(typeof(UserMeta))]
[DisplayColumn("UserName")]
public partial class User
{
}
In my DomainService:
public IQueryable<Message> GetMessages()
{
return this.ObjectContext.Messages.Include("Owner");
}
At last, I had to use Reflection. For DataGrid:
private void OnAutoGenerateColumn(object sender, DataGridAutoGeneratingColumnEventArgs e)
{
//Need to get an array, but should always just have a single DisplayColumnAttribute
var atts = e.PropertyType.GetCustomAttributes(typeof(DisplayColumnAttribute),true);
foreach (DisplayColumnAttribute d in atts)
{
DataGridTextColumn col = (DataGridTextColumn)e.Column;
//Make sure that we always have the base path
if(col.Binding.Path.Path!="")
{
col.Binding = new Binding()
{
Path = new PropertyPath(col.Binding.Path.Path + "." + d.DisplayColumn)
};
}
//Only do the first one, just in case we have more than one in metadata
break;
}
}
And for Telerik RadGridView:
var column = e.Column as GridViewDataColumn;
if (column == null)
{
return;
}
// Need to get an array, but should always just have a single DisplayColumnAttribute
var atts = column.DataType.GetCustomAttributes(typeof(DisplayColumnAttribute), true);
foreach (DisplayColumnAttribute d in atts)
{
// Make sure that we always have the base path
if (column.DataMemberBinding.Path.Path != "")
{
column.DataMemberBinding = new Binding()
{
Path = new PropertyPath(column.DataMemberBinding.Path.Path + "." + d.DisplayColumn)
};
}
// Only do the first one, just in case we have more than one in metadata
break;
}