I tried to use SubSunsonic.ActiveRecord in SL3 project that uses .NET RIA Services.
However when I try to return some IQuerable in DomainService class I get an error that the classes generated by Subsonic have a property 'Columns' with an unsupported type.
That's what I have
public IEnumerable<SE_NorthWind.SuperEmployee> GetIntegers()
{
return SE_NorthWind.SuperEmployee.All()
.Where(emp => emp.Issues > 100)
.OrderBy(emp => emp.EmployeeID);
}
And this is the error I get
Error 7 Entity 'SE_NorthWind.SuperEmployee' has a property 'Columns' with an unsupported type. SuperEmployee
Any idea what to do? Don't really wanna use Linq to SQL :)
Thx
P.S. Just tried to LinqTemplates from SubSonic, but this solution I get the error
Error 4 The entity 'SE_NorthWind.SuperEmployee' does not have a key defined. Entities exposed by DomainService operations must have must have at least one property marked with the KeyAttribute. SuperEmployee
of course SuperEmployee table has a primary key, cause the classes generated by SubSonic can see it
...
Columns.Add(new DatabaseColumn("EmployeeID", this)
{
IsPrimaryKey = true,
DataType = DbType.Int32,
IsNullable = false,
AutoIncrement = true,
IsForeignKey = false,
MaxLength = 0
});
...
But RIA objects, they need some attributes. I guess I'll have to go with native Linq To SQL until SubSonic adapts to all this :(
To answer the second part of your question.
You need to add the "KeyAttribute" to the PrimaryKey property on the "EmployeeId" property.
The attribute is in the "System.ComponentModel.DataAnnotations" namespace.
No up on Sub Sonic 3, but you could change the underlying template to generate this, or change the sub sonic engine and submit it as a patch.
I'm running with SilverLight 3 with RaiServices.
Hope this helps.
Can you try removing the [EnableClientAccess()] attribute to see if your project will build?
Related
I have used breeze's CreateEntity a few times when table's PK is a user-entered value. And a few times with SQL SERVER when PK is an IDENTITY. This is my first time trying to do it when PK is autogenerated ID (actually a "sequence") in ORACLE. It isn't working.
I do check first to make sure I have fetched the Metadata then create the new, empty entity that will be filled in with values by user.
My code to createEntity (newEntity is a knockout Observable):
function createEntity(newEntity) {
newEntity(manager.createEntity(entityNames.escctransactions, {})); <<<<< this fails
return;
}
The Error:
Cannot attach an object of type (ESCC_TRANSACTIONS:... ) to an EntityManager without first setting its key or setting its entityType 'AutoGeneratedKeyType' property to something other than 'None'
I know I need to set the AutoGeneratedKeyType to "Identity" but not sure how to do it. Tried this when I'm inititalizing the metadata, but still getting same error so it's obviously not working:
var entyType = manager.metadataStore.getEntityType("ESCC_TRANSACTIONS");
entyType.setProperties({ AutoGeneratedKeyType: AutoGeneratedKeyType.Identity });
I've seen something about doing it in a constructor but I've never used a constructor in JavaScript. Also something about changing it in a config?
Using Breeze 1.6, Knockout.js 3.4, .NET 4.5.2 framework
THANKS
Figured it out myself and it's working now. The code to set AutoGeneratedKeyType is as follows:
var entityType = manager.metadataStore.getEntityType("ESCC_TRANSACTIONS");
entityType.autoGeneratedKeyType = "Identity";
Or this works:
var entityType = manager.metadataStore.getEntityType("ESCC_TRANSACTIONS");
entityType.autoGeneratedKeyType = breeze.AutoGeneratedKeyType.Identity;
And in spite of the Breeze documentation for AutoGeneratedKeyType here:
http://breeze.github.io/doc-js/api-docs/classes/AutoGeneratedKeyType.html, it's not a capital "A" in Auto, it's a small "a".
I have a C# EF 6 Database First project("DocRetData") that I am using as my "Model" in a VB.Net Web Forms project. I'm also using the "Web Forms Scafolding" extension. I have added a reference to the EF project and then created "New Scaffold Item". Project compiles. When I run it and access the "Default" page it lists items just fine, but when I go to Edit or Create a new item I get System.ArgumentNullException in the GetData() function of ForeignKey_EditField Class. It looks like this:
Public Function GetData() As IQueryable
Dim entityType = Type.[GetType](Me.DataTypeName)
Return _db.[Set](entityType).AsQueryable()
End Function
This has to be something do with a reference conflict of some kind, because if I remove Data Project, add the Model as a class within the Web Forms project and go through all the same steps then I don't get the error and can Edit or Create items just fine.
The data structure here is a fairly simple one. The Table(Object) I'm trying to reference here is has the following structure:
[AppSettingID] [int] IDENTITY(1,1) NOT NULL,
[CountyID] [int] NOT NULL,
[Name] [varchar](30) NOT NULL,
[VariableName] [varchar](50) NOT NULL,
[Setting] [varchar](4000) NOT NULL,
[FieldDataTypeID] [int] NOT NULL,
where CountyID and FieldDataTypeID are foreign keys to other tables.
The Error occurs on the Return statement because the entityType is null. The Me.DataTypeName is "DocRetData.County". I'm guessing this has something to do with the way that VB.Net does/does not handle Namespaces but have not been able to track it down.
Thanks
dbl
Im not sure how it would apply to VB but in C# this is the change you need to make if the Type exists in a different class library
public IQueryable GetData()
{
var entityType = Type.GetType(this.DataTypeName + ",DAL");
return _db.Set(entityType).AsQueryable();
}
So in my example my Class Library where my Entities exists is Called DAL. My DataTypeName was "DAL.tbl_Jobs"
So Type.GetType("DAL.tbl_Jobs,DAL") return the Entity Type.
Hope this helps
I'm querying my service using a url like:
http://a.com:3080/odata/DiscussionVM(6)?$expand=Section,User
on controller method:
[EnableQuery(MaxExpansionDepth = 7)]
public SingleResult<DiscussionVM> GetDiscussionVM([FromODataUri] int key)
{
return SingleResult.Create(db.DiscussionVMs.Where(discussionVM => discussionVM.DiscussionId == key));
}
This works and returns the correct JSON.
However I then run the slightly more advanced query on a different model:
http://a.com:3080/odata/OrganisationVM(30)?&$expand=Categories($expand=Discussions($expand=Section,User))
and controller action:
// GET: odata/OrganisationVM(5)
[EnableQuery(MaxExpansionDepth = 5, AllowedQueryOptions = AllowedQueryOptions.All)]
public SingleResult<OrganisationVM> Get([FromODataUri] int key)
{
return SingleResult.Create(db.OrganisationVMs.Where(organisationVM => organisationVM.OrganisationId == key));
}
this returns the below DiscussionVM JSON:
{
#odata.type: "#Models.DiscussionVM",
DiscussionId: 6,
Section_SectionID: 1005,
User_Id: "4cecc52e-ac3a-4696-ac6c-175af2a6378a",
DateCreated: "2014-12-06T00:00:00Z",
OrgCat_OrganisationCategoryId: 1,
Text: "Dummy section",
Html: null,
IsUserCreated: true,
Organisation_OrganisationId: null,
Positives: null,
Negatives: null,
CommentCount: 1
}
But contains no User or Section object. No error is thrown. The correct objects are queried (profiled) in the database and data including user and section are returned.
I discovred that oData needs the expanded entities to be referenced in its Edm Model.
if not it will stop expanding after the first level, that's why further expands will not work.
Just add your expandable EntitySet to the ODataConventionModelBuilder in your IEdmModel (in MapODataServiceRoute's model config) :
var builder = new ODataConventionModelBuilder();
// ...
builder.EntitySet<Categories>("categories");
// ...
Hope this helps.
From what Brad and I have gathered in this SO answer, it could be a matter of mixing complex types with entity types. Expand plays very well if all your types are entities, but if you mix both, you end up with weird behavior like you and I are having.
If you do mix them, the expand cascade has to start with entity types and end with complex types. The expand chain seems to end where a complex type has an entity type property.
This could come from v3 where a complex type referring to an entity type was flat not supported. It is in V4 but it is not totally clean with WebAPI as we can see.
The lack of documentation and support on the matter makes it difficult to claim this is the absolute truth, but at least it explained my situation and made my stuff work. Hope it helps you too.
I have never seen your $expand syntax before. Where did you get it from? I think you must expand your query the following way:
http://a.com:3080/odata/OrganisationVM(30)?$expand=Categories/Discussions/Section,Categories/Discussions/User
Assuming Odata V4, here are some examples of the standard.
I've seen in OData documentation that there are Edm types Date and Time. Currently in my database there are many DATE fields being represented in EF as DateTimes, so the ODataConventionModelBuilder is declaring them as Edm.DateTime. How can I change them to Edm.Date?
Was hoping I could do this:
entityType.Property(p => p.AgreementDate).EdmType = EdmType.Date;
The corresponding Edm type of certain property is mapped from the CLR type and can't be overrided by ODataConventionModelBuilder.
If you want to change the Edm type, you can ignore these properties within the ODataConventionModelBuilder.
After getting the Edm model by calling GetEdmModel on the ODataConventionModelBuilder, you can add these properties with Edm.Date to the Edm model by calling OData APIs.
Here's my answer in case someone is interested in the details of how to implement Feng Zhao's suggestion. I didn't find the API too discoverable, so I wanted to share.
First, build your EDM model as usual with the ODataConventionModelBuilder but ignore the date property:
...
entitType.Ignore(p => p.AgreementDate);
...
IEdmModel model = builder.GetEdmModel();
Then add the date property "manually":
var myType = (EdmStructuredType)model.FindDeclaredType(typeof(MyType).FullName);
var dateType = (IEdmPrimitiveType)model.FindType("Edm.Date");
myType.AddProperty(new EdmStructuralProperty(myType, "AgreementDate", new EdmPrimitiveTypeReference(dateType, false)));
That's it.
Im in a bit of a jam.
Problem
NHibernate forces me to make a foreignkey column nullable, which is a very bad idea for our database and quite ugly.
Is there a work around for this?
Situation
I have the following maps (names changed for simplicity):
public class BillMap : SequenceGeneratedIdEntityMap<Bill>
{
public BillMap()
{
Id(x => x.Id).GeneratedBy.Native("BILL_SEQ");
... (maps) ...
HasMany<Expense>(f => f.Expense)
.Schema("ACCOUNT")
.Table("EXPENSE")
.KeyColumn("BILL")
.Cascade.All();
}
}
public class ExpenseMap : SequenceGeneratedIdEntityMap<Expense>
{
public ExpenseMap ()
{
Id(x => x.Id).GeneratedBy.Native("EXPENSE_SEQ");
... (maps) ...
}
}
Using these maps I get the following from NHibernate when saving an instance of Bill:
select ACCOUNT.BILL_SEQ.nextval from dual
select ACCOUNT.EXPENSE_SEQ.nextval from dual
command 0:INSERT INTO ACCOUNT.BILL(...)
command 0:INSERT INTO ACCOUNT.EXPENSE(...)
command 0:UPDATE UPDATE.EXPENSE SET BILL = X WHERE ...
Notice 2 things here:
All id's are requested from the sequences BEFORE the inserts.
The foreignkey is not updated until AFTER the expense has been inserted.
This forces me to make the column nullable AND to allow updates on the table.
Ideally the update statement should not be necessary and handled some deep dark place inside NHB :).
This could be solved by making a bidirectional reference, but that would destroy my model :/.
I do believe this a returning issue for me (never found a good solution before). Are there anyone who knows of workaround?
Kind regards
By setting .Inverse() on your HasMany<Expense> call, NHibernate will be aware of which side is the 'parent' object. I believe that will swap the order of the inserts.
For more information:
http://wiki.fluentnhibernate.org/Getting_started#Mappings
Inverse Attribute in NHibernate