Existing XSD Snippet:
<xs:element name="searchcriteria">
<xs:complexType>
<xs:sequence>
<xs:element ref="filter"
minOccurs="0"
maxOccurs="unbounded" />
</xs:sequence>
<xs:attribute name="Request"
type="RequestType" />
</xs:complexType>
</xs:element>
<xs:element name="filter">
<xs:complexType>
<xs:sequence>
<xs:element ref="filter"
minOccurs="0"
maxOccurs="unbounded" />
</xs:sequence>
<xs:attribute name="FieldName"
type="FieldNameType" />
</xs:complexType>
</xs:element>
...
RequestType : Enumeration of 2 values R1 and R2
FieldNameType : Enumeration of 2 values F1, and F2
Now i want to modify this XSD to provide a validation that :
When RequestType = R1, Then Alowed Fields names are F1 and F2
When Request Type = R2, Then allowed Fields names are F1, F3 and F4. ( May be a new enumeration is required)
How can i add such validations ?
Thanks.
The basic idea of XSD (and most other XML schema languages) is to bind validation behavior to element types. If you want one set of instances validated one way and another set of instances validated another way (goes the idea), it's prima facie evidence that they are actually two distinct types of elements, and should have two distinct names.
So the simplest way to make XSD validate your requests as you describe is to replace your searchcriteria element with a pair of elements named R1 and R2. Declare them with different types, as you wish: either they each have an element named filter with an attribute carrying an appropriate enumerated type, or R1 is declared as having either an F1 or an F2 as a child, and R2 is declared as having a choice of F1, F3, or F4.
If you can't or won't do this, you can use XSD 1.1 and its conditional type assignment feature to declare two types for searchcriteria (the two types you would otherwise have used for R1 and R2) and assign the appropriate type based on the value of the Request attribute. You can also use assertions on searchcriteria to check the co-constraint.
If you don't have access to an XSD 1.1 validator, tell the vendor of your XSD 1.0 validator that you'd like an upgrade, and explore the use of Schematron assertions to check the constraint.
See also this essentially similar question for more concrete discussion of the options, with examples.
Related
I'm trying to map an entity property in such way that it writes its value to a database column but retrieves its value using a formula.
To focus on the actual issue, I have simplified the example. In reality the formula is a bit more complex and is using an NHibernate filter.
<many-to-one cascade="all" class="Thing" lazy="false" name="MyThing"
formula="(SELECT Things.Value FROM Things WHERE Things.Id = MyThingId)">
<column name="MyThingId" />
</many-to-one>
The formula is ignored however, unless I remove the <column name="MyThingId" /> line.
How would I fix this mapping in order to have NHibernate use the formula?
I don't think it's possible to do exactly what you are trying.
Why not split the property in two? One readonly for the formula and the other read/write with a direct column mapping...
If you still want a single access point, you can map a third ignored propery that implements it's get and set accessors with the two first properties.
Basically:
[DataContract(Namespace = "http://www.abc.com/foo" Name = "Get{0}Request")]
public class GetGenericRequest<T> { ... }
my WSDL has this verbatum:
<xs:complexType name="GetFooRequest">
<xs:annotation>
<xs:appinfo>
<GenericType xmlns="http://schemas.microsoft.com/2003/10/Serialization/" Name="Get{0}Request" Namespace="http://www.abc.com/foo">
<GenericParameter Name="Foo" Namespace="http://www.abc.com/foo"/>
</GenericType>
</xs:appinfo>
</xs:annotation>
<xs:sequence>
<xs:element xmlns:q2="http://schemas.microsoft.com/2003/10/Serialization/Arrays" minOccurs="0" name="Ids" nillable="true" type="q2:ArrayOfint"/>
</xs:sequence>
</xs:complexType>
<xs:element name="GetFooRequest" nillable="true" type="tns:GetFooRequest"/>
So, looking at that it just does not seem that this would be interoperable. It has the extra "appinfo" stuff that would probably throw things off for Java or PHP right? or would they just ignore that?
Also, what's even more strange is that whether I use int[] or ICollection<int>, etc it still makes the type ArrayOfint (which, I get that it changes all underlying collections that it understands to an array. But, is that naming interoperable?)
It is interoperable - for clients it's just as if you have a non-generic class, named GetFooRequest. As for the collections, again, the name doesn't (or shouldn't) matter, as long as the schema of the element <xs:sequence> of <xs:int>, is "standard".
I am working on an ASP.NET Web application that uses NHibernate and I have noticed something funny.
So I have an object Document which I would make into an abstract class and 2 concrete implementations Document1 and Document2.
I tried to write the mappings for them applying the table-per-subclass strategy as described in the documentation(link text):
<class name="Document" abstract="true">
<id name="Id">
<generator class="identity"/>
</id>
...
<class>
<joined-subclass
name="Document1"
extends="Document" >
<key column="ParentId"/>
...
</joined-subclass>
<joined-subclass
name="Document2"
extends="Document" >
<key column="ParentId"/>
...
</joined-subclass>
Now this is how I obtain objects from the session in my application:
public TEntity GetById<TEntity>(object id) {
return Session.Get<TEntity>(id);
}
Now my problem is that when I do:
GetById<Document>(1)
for example, I don't get a Document object I get an object of type Document1 or Document2 depending on which type that object is.
I tryed using the table-per-subclass with discriminators strategy as mentioned in the documentation(link above) and I set join=select and lazy=false on the abstract object to get it to return an object of type Document but nothing worked.
The code works but it doesn't seem right. I have a left join where I could not use one.
Isn't there a way to just get the abstract object or does nhibernate actually instantiate the objects it returns which would make this impossible? Is it possible?
I have the feeling that I am getting more info than I need.
You'll never get the abstract class because the whole point of an abstract class is that you can't instantiate one. Besides your code will return only the Document facade to the rest of your code anyway. So I'm not sure what the problem really is.
It is not possible to retrieve an instance of Document1 or Document2 that only populates the properties that are defined in the abstract class. In .NET, you are always working with an instance of a concrete class even if the type is declared as an interface or abstract class.
I know one of the breaking changes with NHibernate 2.* is that the NHibernate.Nullables are no longer supported. Therefore, what do you use in your mapping file to map the nullable DateTime? type? For i.e.:
Understandably doesn't work:
<property name="CreateDate" column="CreateDate" type="DateTime?" not-null="false" />
And no longer supported:
<property name="ModifiedDate" column="ModifiedDate" type="Nullables.NHibernate.NullableDateTimeType, Nullables.NHibernate" not-null="false"/>
I know it must be so obvious, but I'm not finding it!
Answer is as simple as:
NHibernate will reflect over the class in question and discover that the property's reflected type is DateTime? all on its own.
Thanks #Justice!
<property name="CreatedDate" />
NHibernate will reflect over the class in question and discover that the property's reflected type is DateTime? all on its own.
NHibernate will assume the column name is by default the same as the property name, unless you tell it otherwise.
NHibernate will assume that any property is nullable (not-null="false") unless you tell it otherwise.
If you really want, it should be something like ...
<property name="CreatedDate" type="System.Nullable`1[[System.DateTime, mscorlib]], mscorlib" />
Edit: Ryan raised a good point. I specifically want to be able to map to and from while still storing human-readable values in the database. That is, I don't want a bunch of enumeration integers in my database.
According to the documentation you can either leave the type attribute of the property in your mapping file blank or you define it and specify the class name of the enumeration.
Another way would be to convert the enumeration to an int and use the int as the mapped type.
You have to implement a custom IUserType. See this post.
I've never used NHibernate, but can't you just set the SQL datatype to int?
I think you can just set the type to string:
<property name="EnumProperty" Type="string" Length="50" NotNull="true" />