EF and WPF Datagrid binding issue - entity-framework

Is it possible to change the name of the server the EF connect to on the fly?
I have the same database on 5 servers (different environments, Dev, Test, UAT...) and would like to write a dashboard application to extract the same information from each server in turn by just selecting the environment from a DDL.
I am using Entity Framework 4/WPF/C#. The new ObservableCollection(context.EntitySet) is bound to the WPF DataGrid in XAML. This works fine.
the xaml grid binding is as follow
<grid:RadGridView ItemsSource="{Binding EPolicies}" IsReadOnly="True" RowDetailsVisibilityMode="VisibleWhenSelected" RowIndicatorVisibility="Collapsed" AutoGenerateColumns="False">
in the view model I call the following code
entities = new EpolicyEntities(environmentConnStr);
customTexts = new ObservableCollection<C_CustomTextType>(from i in entities.C_CustomTextType select i);
languages = new ObservableCollection<C_Language>(from i in entities.C_Language select i);
userTypes = new ObservableCollection<C_UserType>(from i in entities.C_UserType select i);
EPolicies = new ObservableCollection<EPolicy>(from e in entities.EPolicies select e);
entities is the ObjectContext representing the database that I connect to
The first time it works fine but the second time even thoguh I can see the new values in the EPolicies object, the grid is not being refreshed as I would want
EPolicies is a property defined as below
public ObservableCollection EPolicies
{
get { return ePolicies; }
set
{
ePolicies = value;
OnPropertyChanged(() => EPolicies);
}
}
Can somebody help me please?
thanks
Anyone done this?

Okay I found out.
The issue was that the property
public ObservableCollection EPolicies {
get { return ePolicies; }
set {
ePolicies = value; OnPropertyChanged(() => EPolicies);
}
}
is calling the OnpropertyChanged but not the Base.OnPropertyChanged.
Not sure why it works that way might be that the event is not being bubbled up.
Does anybody has an answer?

Related

How to replace an existing collection on an Entity Frameworks POCO object

Let's say I create a new Entity and Save it as follows:
UserReport report = new UserReport() {//set the props}
manager.SaveUserReport(report)
Public UserReport SaveUserReport(UserReport report)
{
using(var context = new ReportDatabase())
{
context.UserReports.AdObject(report);
context.SaveChanges();
}
return report;
}
so far so good
I then read back the saved Report
savedReport = manager.GetUserReports(new int[] {report.Id}).FirstOrDefault();
Public List<UserReport> GetUserReports(IEnumerable<int> reportIds)
{
using (var context = new ReportDatabase())
{
var reports = from UserReport in context.UserReports
where reportIds.Contains(userReport.Id)
select userReport;
return visibleReports.ToList();
}
}
savedReport is now an attached UserReport
The UserReport object has a collection of Columns attached to it.
I want to replace the set of Columns attached with another set (that already exist in the database).
savedReport.Columns = newColumnCollection
This fails with the error "The property Columns" on type UserReport_etc' cannot be set because the collection is already set to an EntityCollection"
I've looked at this article: the problem is the same, but I cannot use that solution.
What is the correct way to tackle this?
OK - looks like it's just a case of setting the non-navigation properties to not be virtual.
That is one hell of a weird situation, given that the behaviour that is modified is of properties that remain as virtual.

EF 4.0 Dynamic Proxies POCO Object Does not match target type

I am using EF 4.0 and POCO's. I stumbled across this error while inserting to records into the data base.
Property accessor 'QualityReasonID' on object 'BI.Entities.QualityReason' threw the following exception:'Object does not match target type.'
There errors occur on the Databind to a GridView after saving a new record to the database. I identified what is happening but I am not sure WHY it is occurring or If I am using EF/POCO's incorrectly. Any insight would be appreciated.
The exception is occuring because the object types in the IEnumerable are not the same.
The orginal entrys in the table are of type System.Data.Entity.DynamicProxies.QualityReason_E483AD567288B459706092F1825F53B1F93C65C5329F8095DD1D848B5D039F04}
While the new one is BI.Entities.QuailtyReason.
Here is how I insert the new object.
public void createQualityReason(QualityReason qReasons)
{
dbcontext.QualityReasons.AddObject(qReasons);
dbcontext.SaveChanges();
}
I resolved the error by changing the fetch code from:
public IEnumerable<QualityReason> fetchQualityReasons()
{
IEnumerable<QualityReason> queryReasons = dbcontext.QualityReasons.AsEnumerable();
return queryReasons;
}
to
public IEnumerable<QualityReason> fetchQualityReasons()
{
IEnumerable<QualityReason> queryReasons = from data in dbcontext.QualityReasons.AsEnumerable()
select new QualityReason
{
QualityReasonID = data.QualityReasonID,
QualityReasonName = data.QualityReasonName
};
return queryReasons;
}
So to get around the error I have to select into the POCO class explicitly each time. This feels like I am going something wrong. Any thoughts?
The error is caused because GridView does not handle polymorphic datasources when using boundfields. So you have two options
Use TemplateFields instead which can handle polymorphic datasources, this may changing some of your front end code and GridView events.
Use Linq to create a non-polymorphic databsource that the boundfields can handle
So instead of using something like ti
gvGroups.DataSource = ProductHelper.Get()
gvGroups.DataBind();
var query = from p in ProductHelper.Get()
select new {p.ProductId, p.ProductName, p.ProductDesc, p.ProductLink};
gvGroups.DataSource = query;
gvGroups.DataBind();
I don't know if the problem has been solved yet, but I've had the same problem with my (POCO) "Scenario" class.
The problem disappeared when using a context.CreateObject<Scenario> to create the (POCO) object i.s.o. a .... = new Scenario().
Faced the same issue today and used Value Injecter to solve it. It's as simple as:
var dynamicProxyMember = _repository.FindOne<Member>(m=>m.Id = 1);
var member = new Member().InjectFrom(dynamicProxyMember) as Member;
That's it :)

RIA Services EntitySet does not support 'Edit' operation

Making my first steps in RIA Services (VS2010Beta2) and i encountered this problem:
created an EF Model (no POCOs), generic repository on top of it and a RIA Service(hosted in an ASP.NET MVC application) and tried to get data from within the ASP.NET MVC application: worked well.
Next step: Silverlight client. Got a reference to the RIAService (through its context), queried for all the records of the repository and got them into the SL application as well (using this code sample):
private ObservableCollection<Culture> _cultures = new ObservableCollection<Culture>();
public ObservableCollection<Culture> cultures
{
get { return _cultures; }
set
{
_cultures = value;
RaisePropertyChanged("cultures");
}
}
....
//Get cultures
EntityQuery<Culture> queryCultures = from cu in dsCtxt.GetAllCulturesQuery()
select cu;
loCultures = dsCtxt.Load(queryCultures);
loCultures.Completed += new EventHandler(lo_Completed);
....
void loAnyCulture_Completed(object sender, EventArgs e)
{
ObservableCollection<Culture> temp=
new ObservableCollection<Culture>loAnyCulture.Entities);
AnyCulture = temp[0];
}
The problem is this: whenever i try to edit some data of a record (in this example the first record) i get this error:
This EntitySet of type 'Culture' does not support the 'Edit' operation.
I thought that i did something weird and tried to create an object of type Culture and assign a value to it: it worked well!
What am i missing? Do i have to declare an EntitySet? Do i have to mark it? Do i have to...what?
Thanks in advance
It turns out that in the DomainService class one has to implement (or at least to mark "placeholder methods") as "Edit", "Delete",... eg
[Delete]
public void DeleteCulture(Culture currentCulture)
{
throw new NotImplementedException("UpdateCulture not Implemented yet");
}
[Insert]
public void InsertCulture(Culture newCulture)
{
throw new NotImplementedException("InsertCulture not Implemented yet");
}
This way the OrganizationDomainContextEntityContainer class creates an EntitySet with parameter EntitySetOperations.All (meaning that all the CUD operations are available).
Hope it's useful for someone in the future!

Retrieval of Single Entity + Ria Services

I am reading and doing some RnD on RIA as a solution for a new Silverlight project.
I have read alot of the documentation and decided to do a small mockup of a system using .Net RIA Services.
I want to know how to get a Single Entity from the Domain Service?
example:
I want to get a person and populate a form:
public Person GetSinglePerson()
{
return new Person { ID = 4, FirstName = "Cyanide", LastName = "Happiness", Status=3 };
}
Say I use the the DomainDataSource:
<riaControls:DomainDataSource x:Name="source2" QueryName="GetSinglePersonQuery" AutoLoad="True">
<riaControls:DomainDataSource.DomainContext>
<web:DataContext/>
</riaControls:DomainDataSource.DomainContext>
</riaControls:DomainDataSource>
This only returns a EntityCollectionView? How do I bind for example in a form to properties that are in the Person Class?
Like:
<TextBox Text="{Binding FirstName, ElementName=source2}"/>
Everything seems to come back as IEnumerable or as CollectionViews (like the DATA binding in the samples) which aren't useful for a single entity.
I want a single persons entry, why do I want a CollectionView in which I cannot access properties directly.
I have also use the:
LoadOperation<Person> oLoadOperation = oDataContext.Load(oDataContext.GetSinglePersonQuery());
I am very close to giving up on this RIA idea and just going with a normal WCF service as it is more predictable and manageable at this stage.
ctxt.Load(ctxt.GetEmployeeByNumberQuery("ABC123")).Completed += new System.EventHandler(EmployeeLoad_Completed);
void EmployeeLoad_Completed(object sender, System.EventArgs e)
{
Employee myEmployee = (sender as LoadOperation<Employee>).Entities.FirstOrDefault();
}
hey just found this check it out I think this is what you want to do
http://jeffhandley.com/archive/2009/11/10/domaindatasource-single-record.aspx
HumanResourceContext context = new HumanResourceContext();
var addressquery = context.GetAddressesQuery();
addressquery = addressquery.Where(a => a.AddressId == 1);
context.Load(addressquery, (op) =>
{
Address address = op.Entities.FirstOrDefault();
MessageBox.Show(address.Street1);
}, null);
I presume you have your class decorated with [EnableClientAccess] ?
try
<TextBlock Text="{Binding Path=Person.FirstName}"

Entity Framework and Entity Tracker Problems

If I run the following code it throws the following error:
An entity object cannot be referenced by multiple instances of IEntityChangeTracker
public void Save(Category category)
{
using(var db = new NorthwindContext())
{
if(category.CategoryID == 0)
{
db.AddToCategorySet(category);
}
else
{
//category.RemoveTracker();
db.Attach(category);
}
db.SaveChanges();
}
}
The reason is of course that the category is sent from interface which we got from GetById method which already attached the EntityChangeTracker to the category object. I also tried to set the entity tracker to null but it did not update the category object.
protected void Btn_Update_Category_Click(object sender, EventArgs e)
{
_categoryRepository = new CategoryRepository();
int categoryId = Int32.Parse(txtCategoryId.Text);
var category = _categoryRepository.GetById(categoryId);
category.CategoryName = txtUpdateCategoryName.Text;
_categoryRepository.Save(category);
}
I'm still learning Entity Framework myself, but maybe I can help a little. When working with the Entity Framework, you need to be aware of how you're handling different contexts. It looks like you're trying to localize your context as much as possible by saying:
public void Save(Category category)
{
using (var db = new NorthwindContext())
{
...
}
}
... within your data access method. Did you do the same thing in your GetById method? If so, did you remember to detach the object you got back so that it could be attached later in a different context?
public Category GetById(int categoryId)
{
using (var db = new NorthwindContext())
{
Category category = (from c in db.Category where Category.ID == categoryId select c).First();
db.Detach(category);
}
}
That way when you call Attach it isn't trying to step on an already-attached context. Does that help?
As you pointed out in your comment, this poses a problem when you're trying to modify an item and then tell your database layer to save it, because once an item is detached from its context, it no longer keeps track of the changes that were made to it. There are a few ways I can think of to get around this problem, none of them perfect.
If your architecture supports it, you could expand the scope of your context enough that your Save method could use the same context that your GetById method uses. This helps to avoid the whole attach/detach problem entirely, but it might push your data layer a little closer to your business logic than you would like.
You can load a new instance of the item out of the new context based on its ID, set all of its properties based on the category that is passed in, and then save it. This costs two database round-trips for what should really only need one, and it isn't very maintainable.
You can dig into the context itself to mark the Category's properties as changed.
For example:
public void Save(Category category)
{
using (var db = new NorthwindContext())
{
db.Attach(category);
var stateEntry = db.ObjectStateManager.GetObjectStateEntry(category);
foreach (var propertyName in stateEntry.CurrentValues.DataRecordInfo.FieldMetadata.Select(fm => fm.FieldType.Name)) {
stateEntry.SetModifiedProperty(propertyName);
}
db.SaveChanges();
}
}
This looks a little uglier, but should be more performant and maintainable overall. Plus, if you want, you could make it generic enough to throw into an extension method somewhere so you don't have to see or repeat the ugly code, but you still get the functionality out of it.