I can't make this seemingly simple call on my DomainService compile. I keep getting 'Operation named 'ComposeNewOrder' does not conform to the required signature. Parameter types must be an entity type or one of the predefined serializable types.'
Am I missing something here, should I be doing it in another way or is it just unsupported? (I'm using WCF RIA services 1.0 for VS2010)
public class ComposedOrder
{
[Key]
public Order Order { get; set; }
public OrderPart[] Parts { get; set; }
}
public class MyDomainService{
...
[Invoke]
public void ComposeNewOrder(ComposedOrder co)
{
//implementation
}
...
}
I have CRUD operations defined for Order and OrderPart which are entities from my EntityFramework model.
Invoke operations cannot take Entity types (such as your ComposedOrder) as parameters. You can only use data types, such as int, string etc. You could pass in the key of your ComposedOrder and load it using that.
I have actually written an invoke method passing it a entity argument and it works.
Related
I am consuming a REST Xml service.
I have all the necessary classes to do this, (supplied by the dev who wrote the service) but at my end I have to save some of the responses to the DB to perform the tasks of the app I am writing.
So I have marked some of these classes I need to put in the DB as partial and extended them so that I can inherit from a DbEntity class which specifies an ID property so I can use EF to save them to the DB thus:
public interface IDbEntity
{
int ID { get; set; }
}
[Serializable]
public class DbEntity : IDbEntity
{
[IgnoreDataMember]
[XmlIgnore]
public int ID { get; set; }
}
the problem I am facing now, is that when the service call is being de-serialized I get the error
Error in line 1 position 113. 'Element' 'ElementName' from namespace '' is not expected. Expecting element '_x003C_ID_x003E_k__BackingField'
I am simply making the call like this:
var response = await client.PostAsXmlAsync<TReq>("Some/API/Call", req);
TResp val = await msg.Content.ReadAsAsync<TResp>(response)
all the properties in the original classes have Orders specified with their DataMember attributes and I have clearly marked my DB properties to be Ignored, but to no avail.
is there any way I can get this to work? - ie getting the DataContractSerializer to actually ignore the properties I have marked to be ignored when de-serializing?
as an aside, these ignored properties are also being passed to the service when making a call - does IgnoreDataMember actually do anything?
seems that the way to do this is like this
public interface IDbEntity
{
int ID { get; set; }
}
[Serializable]
[DataContract]
public class DbEntity : IDbEntity
{
[XmlIgnore]
public int ID { get; set; }
}
so basically adding the DataContract Attribute but omitting the DataMember attribute on the item you don't want
don't know how I missed that first time around. seems its opt in rather than opt out in this instance.
I have an entity that looks like this
public class SlideSet {
public SlideSet(string name) : this() {
Name = name
}
public SlideSet() {
Params = new HashSet<SlideSetParameter>();
}
[Required]
public string Name { get; set; }
public virtual ICollection<SlideSetParameter> Params { get; set; }
}
I just noticed that I'm not actually using the second constructor ever and that it actually makes no sense in my domain so I made it private. All of a sudden the Params array stopped loading and always gives me a length of 0. What's going on? In order for it to load I need my constructor to be at least protected. Why?
One of the conditions for EF to be able to create proxies (necessary for lazy loading) is
The class must have a public or protected parameter-less constructor.
From here (an old link, but this part still applies)
The proxy is a derived type and it must be able to call the parameterless constructor of the base type.
You need to have your default constructor set to public, as that is what Entity Framework is going to use to create your objects. Having it as private, it is unable to initialize the Params property, and therefor is trying to add any SlideSetParameters to a null object.
In the EF Code first docs and examples, you'll frequently see classes and methods defined using the partial modifier. For example, the following
public partial class Department
{
public int DepartmentID { get; set; }
public DepartmentNames Name { get; set; }
public decimal Budget { get; set; }
}
I understand the general use of the partial keyword by the C# compiler. However, I often see these examples without applying that functionality (i.e., the class is never re-opened elsewhere).
In other examples, I have also seen partial modifiers on methods as well.
Do these modifiers carry some special meaning in an EF Code First context? Can anyone help me understand what's going on?
Given EF makes working with POCOs really easy, this makes it flexible in terms of separating components and pieces. For example, a section that defines your models:
public partial class PurchaseOrder
{
public Int32 ID { get; set; }
public String CustomerName { get; set; }
public Double InvoiceAmount { get; set; }
public virtual ICollection<PurchaseOrderItem> Items { get; set; }
}
Then apply business logic elsewhere:
public partial class PurchaseOrder : IValidatableObject
{
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
// ...
}
}
And maybe extend its functionality another place still:
public partial class PurchaseOrder
{
public void AddItem(PurchaseOrderItem item)
{
// ...
}
}
though as #E.J. Brennan mentions, it's more likely they were generated from a T4 template. This means that anything you did in the generated file would be wiped with every generation; however, if you left the generated item alone, you could still extend it (like I've shown with IValidatableObject or additional methods) without worrying if your changes would be lost.
It wouldn't be unusual to use T4, or another code generator to create the basic classes that map back to your database. If one did that, you would want those classes to be partial so that you could extend those classes in a seperate file - if you extended those classes in the original file, they would get overwritten every time you re-generated the file.
If you hand coded your classes, there would be no need to use the partial on all of them.
You can extend Entity Framework generated types:
The classes only contain properties that are defined in the conceptual model and do not contain any methods. The generated classes are partial.
So, in your new partial classes (not the generated ones) you can define business logic, display attributes, validation logic etc. These classes won't be overwritten, like the generated ones.
I have an installer like this:
public void Install(IWindsorContainer container, IConfigurationStore store) {
//Services
container.Register(
Classes.FromAssemblyNamed(ASSEMBLY_NAME)
.BasedOn<IService>()
.WithServiceFirstInterface()
.LifestyleTransient());
//Repository
container.Register(
Component.For(typeof(IRepository<>))
.ImplementedBy(typeof(Repository<>))
.LifestyleTransient());
//Contexts
container.Register(
Component.For(typeof(Context<IGlobalObject>))
.ImplementedBy(typeof(GlobalContext<>)).LifestyleTransient());
}
The repository is an open generic, and it has a Context constructor injected, which is a wrapper around an EF DbContext, but takes a type argument to indicate the database it needs to connect to. The idea is that I have several DbContexts as I need to connect to multiple databases, and I want windsor to resolve the appropriate DBcontext based upon the type argument passed to the repository.
The repositories type argument is constrained to the following (GlobalObject and GlobalContext refer to types associated with 1 such database):
public interface IGlobalObject : IObject
{}
public interface IObject
{
int Key { get; set; }
}
However, Windsor cannot resolve the context, and I cannot work out why? It is registered and in the container, but it cannot resolve.
EDIT:
Code for GlobalContext:
public class GlobalContext<T> : Context<T>
where T : IGlobalObject
{
private const string GLOBAL_CSTR = "Global";
public GlobalContext() : base(ConfigurationManager.ConnectionStrings[GLOBAL_CSTR].ConnectionString) {}
public DbSet<Company> Companies { get; set; }
public DbSet<ConnectionString> ConnectionStrings { get; set; }
public DbSet<Server> Servers { get; set; }
}
Context:
//Wrapper around dbcontext which enforces type
public abstract class Context<T> : DbContext where T : IObject
{
protected Context() {}
protected Context(string connectionString) : base(connectionString){}
}
Edit 2:
If i specify the concrete types for every scenario it works, so it is clearly something to do with matching on the interface.
//Contexts
container.Register(
Component.For(typeof(Context<Server>))
.ImplementedBy(typeof(GlobalContext<Server>)).LifestyleTransient());
This looks like a problem to me:
//Contexts
container.Register(
Component.For(typeof(Context<IGlobalObject>))
.ImplementedBy(typeof(GlobalContext<>)).LifestyleTransient());
Here you're saying - when somebody asks for Context inject a GlobalContext<> - the problem being how is windsor meant to know what the generic argument for GlobalContext is.
Its hard to see without seeing your GlobalContext object, but should it be:
container.Register(
Component.For(typeof(Context<>))
.ImplementedBy(typeof(GlobalContext<>)).LifestyleTransient());
This isn't really a direct answer to your question. But I feel the approach may be wrong.
Considering you repositories are implemented by a generic base Repository<> I cant see a clean way of relating the generic Type to the correct context. I think you may need to switch to 'flavoured' repositories with explicit contexts injected into them and/or be more verbose in the way you register your contexts.
I have a project containing POCO entities. A database context has been created for it using Entity Framework 4.2 and code first. This works fine, but the context needs to be exposed as an OData service which does not work.
Browsing to the OData service gives this error:
The property 'DataSubmissionItems' on type
'Lifecycle.ProgramReportSubmission.Model.ProgramReportSubmission' is
not a valid property. Properties whose types are collection of
primitives or complex types are not supported.
The data service class looks like:
public class ExceptionReportDataService : DataService<ExceptionReportEntitiesContext>
{
// This method is called only once to initialize service-wide policies.
public static void InitializeService(DataServiceConfiguration config)
{
config.SetEntitySetAccessRule("*", EntitySetRights.AllRead);
config.DataServiceBehavior.MaxProtocolVersion = DataServiceProtocolVersion.V2;
config.UseVerboseErrors = true;
}
}
The EF context class looks like:
public class ExceptionReportEntitiesContext : DbContext
{
public DbSet<ExceptionReport> ExceptionReports { get; set; }
public ExceptionReportEntitiesContext()
: base(DynamicConfig.GetAppSettingValue("DB_CONN_STRING_LIFECYCLE"))
{
}
}
The POCO entities look like:
namespace WBRT.ProgramData.Lifecycle.ExceptionReportModel
{
public class ExceptionReport
{
public virtual Guid ExceptionReportID { get; set; }
public virtual Lifecycle.ProgramReportSubmission.Model.ProgramReportSubmission ReportSubmission { get; set; }
}
}
namespace Lifecycle.ProgramReportSubmission.Model
{
public class ProgramReportSubmission
{
public Guid ProgramReportSubmissionId { get; set; }
public virtual ICollection<DataSubmissionItem> DataSubmissionItems { get; set; }
}
public class DataSubmissionItem
{
public Guid DataSubmissionItemId { get; set; }
}
}
What I've tried:
Setting DataServiceKey on the DataSubmissionItem class
Setting ProxyCreationEnabled to false on the ExceptionReportEntitiesContext constructor as well as in the data service
Overriding OnModelCreating and removing the IncludeMetadataConvention
Overriding OnModelCreating and setting modelBuilder.Entity<ProgramReportSubmission.Model.ProgramReportSubmission>().Ignore(prs => prs.DataSubmissionItems);
Note: I can't introduce a dependency on the EntityFramework DLL in the POCO entities project as this affects referencing projects that still run .NET 3.5.
Anyone know how to resolve this error?
THe RTM version of WCF DS doesn't support these kind of properties. But the latest CTP does. http://blogs.msdn.com/b/astoriateam/archive/2011/10/13/announcing-wcf-data-services-oct-2011-ctp-for-net-4-and-silverlight-4.aspx.
On the other hand, the fact that you get such an error probably means that WCF DS doesn't recognize the provider as EF, and istead works with it as with a reflection provider. So even the latest CTP won't really fix that problem.
WCF DS currently only recognizes EF provider if the T in DataService is ObjectContext or derived type. The typical workaround for EF Code First is to define the service as DataService and then override the CreateDataSource method on it and return the ObjectContext implementation from your DbContext. See this article about how to do that (it's about EF 4.1, but I think the same will apply to 4.2 as well): http://social.technet.microsoft.com/wiki/contents/articles/5234.aspx. You can skip down to the part about WCF DS.