In many cases it is helpful to separate information access into an interface. OpenAccess provides the functionality to make interfaces persistent. In contrast to a normal persistent class, an interface contains no fields. Potentially the interface hierarchy and the class inheritance hierarchy are not perfect matches, and an interface could also be implemented by many persistent class hierarchies. This makes the use of interfaces ambiguous wrt. Class-table mapping and therefore certain restrictions apply; e.g. it is not possible to include query arguments from an interface in an OQL Query.
Datastore identity, default HIGHLOW key generator
We have a class Address with a reference to an interface ICity. The implementation of this interface is in the class ACity.
 |
The interface is marked as persistent although it cannot define any fields. |
C# |
Copy Code |
[Persistent] public interface ICity { string CityName { get; set; } } [Persistent] public class ACity : ICity { private string acity; public string CityName { get { return acity; } set { acity = value; } } } [Persistent] public class Address { private ICity iCity; public ICity ICityProperty { get { return iCity; } set { iCity = value; } } } |
VB.NET |
Copy Code |
<Persistent()> _ Public Interface ICity Property CityName() As String End Interface <Persistent()> _ Public Class ACity Implements ICity Private acity As String Public Property CityName() As String Get Return acity End Get Set acity = value End Set End Property End Class <Persistent()> _ Public Class Address Private iCity As ICity Public Property ICityProperty() As ICity Get Return iCity End Get Set iCity = value End Set End Property End Class |
The corresponding app.config will not need any additional entries. The default mapping information, present in the app.config file is used.
Datastore identity, HIGHLOW key generator
We advance the model with a second interface that is also declared as persistent:
C# |
Copy Code |
[Persistent] public interface ICity { string CityName { get; set; } } [Persistent] public interface IStreet { string StreetName { get; set; } } [Persistent] public class ACity : ICity, IStreet{ private string acity; private string astreet; public string CityName { get { return acity; } set { acity = value; } }
public string StreetName { get { return astreet;} set { astreet = value;} } } [Persistent] public class Address { private ICity iCity; private IStreet iStreet; public IStreet IStreetProperty { get { return iStreet; } set { iStreet = value; } } public ICity ICityProperty { get { return iCity; } set { iCity = value; } } } |
VB.NET |
Copy Code |
<Persistent()> _ Public Interface ICity Property CityName() As String End Interface <Persistent()> _ Public Interface IStreet Property StreetName() As String End Interface <Persistent()> _ Public Class ACity Implements ICity Implements IStreet Private acity As String Private astreet As String Public Property CityName() As String Get Return acity End Get Set acity = value End Set End Property
Public Property StreetName() As String Get Return astreet End Get Set astreet = value End Set End Property End Class <Persistent()> _ Public Class Address Private iCity As ICity Private iStreet As IStreet Public Property IStreetProperty() As IStreet Get Return iStreet End Get Set iStreet = value End Set End Property Public Property ICityProperty() As ICity Get Return iCity End Get Set iCity = value End Set End Property End Class |
In this case the default mapping in the app.config is enough and no special entries are required.
Application identity - using Int as primary key.
In this sample we have used application identity, and the primary keys are of int type. The only difference between this sample and Datastore identity, HIGHLOW key generator sample is the additional declaration of the identity field. Alternatively, a user defined application identity class could be used.
C# |
Copy Code |
[Persistent] public interface ICity { string CityName { get; set; } } [Persistent] public interface IStreet { string StreetName { get; set; } } [Persistent(IdentityField = “” public class ACity : ICity, IStreet { static private int pk = 0; private int acityid; // pk private string acity; private string astreet; public string CityName { get { return acity; } set { acity = value; } } public string StreetName { get { return astreet; } set { astreet = value; } }
…
[Persistent(IdentityField = “” public class Address { static private int pk = 0; private int addressId; // pk private ICity iCity; private IStreet iStreet;
public IStreet IStreetProperty { get { return iStreet; } set { iStreet = value; } }
public ICity ICityProperty { get { return iCity; } set { iCity = value; } }
public Address() { // addressId = HelperLib.OAHelper.NextNumber(); addressId = pk++; }
public int AddressId { get { return addressId; } set { addressId = value; } } } |
VB.NET |
Copy Code |
<Persistent()> _ Public Interface ICity Property CityName() As String End Interface <Persistent()> _ Public Interface IStreet Property StreetName() As String End Interface <Persistent(IdentityField := acityid)> _ Public Class ACity Implements ICity Implements IStreet Private Shared pk As Integer = 0 Private acityid As Integer Private acity As String Private astreet As String Public Property CityName() As String Get Return acity End Get Set acity = value End Set End Property Public Property StreetName() As String Get Return astreet End Get Set astreet = value End Set End Property
End Class
<Persistent(IdentityField := addressId)> _ Public Class Address Private Shared pk As Integer = 0 Private addressId As Integer Private iCity As ICity Private iStreet As IStreet
Public Property IStreetProperty() As IStreet Get Return iStreet End Get Set iStreet = value End Set End Property
Public Property ICityProperty() As ICity Get Return iCity End Get Set iCity = value End Set End Property
Public Sub New() addressId = System.Math.Max(System.Threading.Interlocked.Increment(pk),pk - 1) End Sub
Public Property AddressId() As Integer Get Return addressId End Get Set addressId = value End Set End Property End Class |
Once again the app.config can stay as it is as it does not require any specific entries.
Application identity - using GUID as primary key
To be able to use Guids instead of ints as a primery key some additional information will be needed in order to get the generation tool to recognize the i_city_id and i_street_id as unique identifiers.
C# |
Copy Code |
[Persistent] public interface ICity { string CityName { get; set; } } [Persistent] public interface IStreet { string StreetName { get; set; } } [Persistent(IdentityField = “” public class ACity : ICity, IStreet {
private Guid acityid; // pk
private string acity; private string astreet; public string CityName { get { return acity; } set { acity = value; } }
public string StreetName { get { return astreet; } set { astreet = value; } } public ACity() { acityid = Guid.NewGuid(); } }
[Persistent(IdentityField = “” public class Address { private Guid addressId; // pk private ICity iCity; private IStreet iStreet;
public IStreet IStreetProperty { get { return iStreet; } set { iStreet = value; } }
public ICity ICityProperty { get { return iCity; } set { iCity = value; } }
public Address() { addressId = Guid.NewGuid(); }
public Guid AddressId { get { return addressId; } set { addressId = value; } } } |
VB.NET |
Copy Code |
<Persistent()> _ Public Interface ICity Property CityName() As String End Interface <Persistent()> _ Public Interface IStreet Property StreetName() As String End Interface <Persistent(IdentityField := acityid)> _ Public Class ACity Implements ICity Implements IStreet
Private acityid As Guid Private acity As String Private astreet As String Public Property CityName() As String Get Return acity End Get Set acity = value End Set End Property
Public Property StreetName() As String Get Return astreet End Get Set astreet = value End Set End Property
Public Sub New() acityid = Guid.NewGuid() End Sub End Class
<Persistent(IdentityField := addressId)> _ Public Class Address Private addressId As Guid Private iCity As ICity Private iStreet As IStreet
Public Property IStreetProperty() As IStreet Get Return iStreet End Get Set iStreet = value End Set End Property
Public Property ICityProperty() As ICity Get Return iCity End Get Set iCity = value End Set End Property
Public Sub New() addressId = Guid.NewGuid() End Sub
Public Property AddressId() As Guid Get Return addressId End Get Set addressId = value End Set End Property End Class |
In this case the app.config entries also need to be changed, in order to explain what kind of classes we accept for the interface references:
app.config |
Copy Code |
<mappings current="mssqlMapping"> <mapping id="mssqlMapping"> <namespace name="Sample4"> <class name="Address"> <field name="iCity"> <extension key="valid-class" value="ACity" /> </field> <field name="iStreet"> <extension key="valid-class" value="ACity" /> </field> </class> </namespace> </mapping> </mappings> |
After these changes the correct columns are generated:
|
Copy Code |
i_city_class int i_city_id uniqueidentifier i_street_class int i_street_id uniqueidentifier |
 |
As of now, the changes in the app.config file need to be done manually. |
Application identity - using GUIDs as primary key, explicit type code
Sometimes its better to hard code the description of the class as shown in this example:
app.config |
Copy Code |
<namespace name="Sample5"> <class name="Address"> <field name="iCity"> <extension key="valid-class" value="ACity=ACITYCLASS" /> <extension key="valid-class" value="BCity=BCITYCLASS" /> </field> <field name="iStreet"> <extension key="valid-class" value="ACity=ACITYCLASS" /> </field> </class> </namespace> |
This makes sure that always the right class id is used and a filled database is usable, even if the class is moved or renamed. If you use the extension valid-class without the type code the automatic class id calculation at start time can fail if the target class has been renamed or moved to another namespace.