Today the DataObjects.Net Team is releasing the first beta of the upcoming 4.5 version of DataObjects.Net.
In this release are included both new providers: for Firebird 2.x & for MySQL 5.x as well as the LINQPad provider.
Both stable versions are also updated to the latest revision. Issues resolved:
- Index attribute on abstract class not in hierarchy root
- No Foreign Key on field from Interface
- Bug of Inheritance with non open generic
- Unsufficient error message when domain build
- Structure field migration
The beta as well as stable versions are available in the download section of the official website.
Please, report any issues concerning new providers so we could fix them before the final version is released. Thanks.
Wednesday, May 18, 2011Tuesday, May 03, 2011DataObjects.Net is updated to build 7487
Hello All,
Today, May 3, both stable versions of DataObjects.Net (v.4.3 & v.4.4) were updated to the latest revision, 7487. Bugs fixed: - Field with type of object is not initialized in DTO on query execution. Here is the detailed scenario, although simplified: public class MyEntity : Entity
{
[Field, Key]
public int Id { get; private set; }
[Field]
public string Text { get; set; }
}
public class DTO1
{
public int Id { get; set; }
public DTO1(MyEntity entity)
{
Id = entity.Id;
}
}
public class DTO2
{
public object DTO1 { get; set; }
}
using (var session = Domain.OpenSession()) {
using (var t = session.OpenTransaction()) {
var q = session.Query.AllUpdates: - Entity.IsMaterializing flag is added to help distinguishing the case when Entity is being materialized from the case when it is being created via ordinary constructor. Usage: // Overriding Entity.OnInitialize method
protected override void OnInitialize()
{
base.OnInitialize();
if(!IsMaterializing)
// Make some new entity initialization logic
}
The updated installers as well as binaries can be downloaded from the official website: dataobjects.net. UPDATE: The detailed scenario is added to the bug fixed.
Labels:
announcements,
website
Wednesday, April 27, 2011DataObjects.Net Contribution Program Rocks!
Hello All!
Today I'm proudly presenting one more participant of the program — Mr. Alexander Ovchinnikov! Alexander is the one who created DataObjects.Net Driver for LINQPad tool. Loud ovation! Let's find out how the power of LINQPad & DataObjects.Net can be utilized: First of all, download LINQPad and install it. Secondly, download the driver. It is named "LINQPadDriver.lpx" and is located in Bin\Latest directory of "Binaries for .NET 4.0" package, build 7475 or later. Next, launch LINQPad application. Click "Add connection" link. In the opened window click "View more drivers..." button. ![]() In the next window click "Browse..." Locate LINQPadDriver.lpx and open it. After that LINQPad will show a message box that the driver is loaded. Select "DataObjects.Net" from the list of available drivers and hit "Next" Connection configuration window will be shown. Here you should set connection name, domain connection url and add all required assemblies with persistent types to the list. I added the one from the upcoming security sample which in turn is based on Northwind model. After several endless seconds, the domain is built and the domain model is populated to the left pane. That's it. Now you can write LINQ queries and execute them. Note that you should start a query with Query.All<Entity> as you usually do in DataObjects.Net-based projects. BTW, look how structures are displayd. Beautiful! SQL tab also works. Don't know why it doesn't provide word wrapping, though =(. Alexander has received DataObjects.Net Ultimate edition as a reward and additionally promised to continue the driver support/maintenance. The driver itself will be included into DataObjects.Net 4.5 and is already available today as a part of DataObjects.Net alpha 2. Developers! Wanna get the license for free? Choose a feature (or more) from the feature list and join da game! The reward is guaranteed.
Labels:
announcements,
community
Monday, April 25, 2011DataObjects.Net stable versions are updated
Hello All,
On Friday, April 22, both stable versions of DataObjects.Net (v.4.3 & v.4.4) were updated to the latest revision. A couple of bugs are fixed: - Persistent interface with paired EntitySet field bug - Alias generator for computed columns was generating not so smart aliases - Upgrade from 4.3 to 4.4 version threw an exception ("No upgrade handler is found for assembly 'Xtensive.Storage', version '1.0.0.0'."). The updated installers as well as binaries can be downloaded from the official website: dataobjects.net
Labels:
announcements,
website
Friday, April 15, 2011On security system, part 4
This is the forth part in a series of posts that is dedicated to security system concept in DataObjects.Net. In the previous part I described Role & Permission types and their relationships in context of entity access based on entity type. This part of the concept answers the question whether a user has access to entities of a persistent type or not and what kind of access if yes (read, write, approve, you name it).
In the part where the requirements were listed there was another set that defines some business rules applied to the set of entities that are accessible to a user. Remember, Sales Representatives can edit only their own Order instances, while Sales Managers can edit both their own orders as well as orders of stuff from their Sales Department and so on. Let me recall the matrix: So, we should have an option to restrict the set of Customers and Orders visible for Sales Representative & Sales Manager roles. These requirements are more like full-fledged business rules applied to the entire set of Customers & Orders than just a security issue, thus they rarely can be implemented in terms of ACL model. Having Permission<T> class we can add there a property that will hold an IQueryable<T> object that will be used to describe the entire set of entities of type T that is accessible to a role that contains the permission. Here is the definition of the Permission<T> class: public class Permission<T> : Permission where T : class, IEntity
{
public Func<SecurityContext, IQueryable<T>> Query { get; protected set; }
...
public Permission(bool canWrite)
: base(typeof(T), canWrite)
{
// If not set explicitly, all entities are accessible by default
Query = context => context.Session.Query.All<T>();
}
public Permission(bool canWrite, Func<SecurityContext, IQueryable<T>> query)
: base(typeof(T), canWrite)
{
Query = query;
}
}
Having such an option, we can use it to explicitly define the accessibility-related business rules. Let's start with Sale Representative. This role restricts access to Order entities to those that are created by particular sales representative. So we have to define a rule that will build an IQueryable<Order> and register it properly. Here is how: public class SalesRepresentativeRole : EmployeeRole
{
private static IQueryable<Order> GetOrdersQuery(SecurityContext context)
{
// Sales representative role has access to its own orders only
return context.Session.Query.All<Order>()
.Where(o => o.Employee == context.User);
}
public SalesRepresentativeRole()
{
RegisterPermission(new OrderPermission(canWrite:true, canApprove:false, GetOrdersQuery));
}
}
I won't focus on SecurityContext for now, The only thing that we should know about it is that it contains a Session and a User. Note that we use Func<SecurityContext, IQueryable<T>> because we need to dynamically resolve the IQueryable<T> depending on the security context, currently active session, etc. Using the same technique we can define restrictions for Sales Manager role: public class SalesManagerRole : SalesRepresentativeRole
{
private static IQueryable<Order> GetOrdersQuery(SecurityContext context)
{
// Sales manager role has access to its own orders as well as to orders of his department
return context.Session.Query.All<Order>()
.Where(
o =>
o.Employee == context.User ||
o.Employee.In(
context.Session.Query.All<Employee>().Where(e => e.ReportsTo == context.User)));
}
public SalesManagerRole()
{
// Sales manager can do sale orders approval, in addition
RegisterPermission(new OrderPermission(canWrite:true, canApprove:true, GetOrdersQuery));
}
}
Note that actually we don't need ACLs or something artificial for defining the restrictions. Imagine a database with thousands and billions of entities and every single one must have one or more records that store entity's owner & all users that should have access to it. That's not an option. Pure business objects from the domain model and their relationships are enough for business rules of almost arbitrary complexity. Now let's define business rules for Sales Representative & Sales Manager roles for accessing Customer objects. There is a rule that says that both of them should deal only with those customers that are from their local region. In this sample there are 2 sales departments, one is located in London, another is in Seattle. Thus, I split all customers into 2 groups: customers from the Old World & customers from the New World. The first group is served by the London sales department, the second one is by the Seattle one. To simplify things I added a helper class that contains 2 groups of countries: public static class WellKnown
{
public static IList<string> NewWorldCountries;
public static IList<string> OldWorldCountries;
static WellKnown()
{
NewWorldCountries = new List<string>()
{
"Argentina", "Australia", "Brazil", "Canada",
"Mexico", "USA", "Venezuela"
};
OldWorldCountries = new List<string>()
{
"Austria", "Belgium", "Denmark", "Finland",
"France", "Germany", "Ireland", "Italy",
"Japan", "Netherlands", "Norway", "Poland",
"Portugal", "Singapore", "Spain", "Sweden",
"Switzerland", "UK"
};
}
}
Having that done, I can describe the customers-related business rule as follow: public class SalesRepresentativeRole : EmployeeRole
{
private static IQueryable<Customer> GetCustomersQuery(SecurityContext context)
{
// Sales representative role has access to local customers only
var employee = (Employee)context.User;
if (employee.Address.Country.In(WellKnown.NewWorldCountries))
return context.Session.Query.All<Customer>()
.Where(c => c.Address.Country.In(WellKnown.NewWorldCountries));
else
return context.Session.Query.All<Customer>()
.Where(c => c.Address.Country.In(WellKnown.OldWorldCountries));
}
public SalesRepresentativeRole()
{
// Sales representative can see and edit customers
RegisterPermission(new Permission<Customer>(canWrite:true, GetCustomersQuery));
}
}
Is't that good? As the role structure is hierarchical, this business rule is automatically inherited by all descendants of Sale Representative role, if not overridden. This means that there is no need to duplicate it in Sales Manager role. However, as Sales President role shouldn't have such a restriction we properly override that permission: public class SalesPresidentRole : SalesManagerRole
{
public SalesPresidentRole()
{
// Overriding the inherited permission with restriction, so this role will have access to all customers
RegisterPermission(new Permission<Customer>());
...
}
}
That's all for today. In the next part I'll describe the SecurityContext class and related stuff in details. Big note for all: The security concept I'm talking about is a prototype. Its purpose is to find out the better way to implement the security in DataObjects.Net. The only way I can see this can be done right is to criticize & discuss the thing before it is implemented and released. I know that the most of DataObjects.Net users are mature and experienced developers that have numerous properly built applications that have their own security systems. Therefore, I'm hoping that it will be better to join our efforts and make the security system that will perfectly fit our needs. For now, I would like to specially thank Vlad Klekovkin for his critics of the prototype. Vlad also shared a concept of his own security system built on top of DataObjects.Net. Thanks a lot, Vlad!
Labels:
architecture,
security
Wednesday, April 13, 2011DataObjects.Net 4.5 Alpha 1
We are pleased to announce the availability of DataObjects.Net 4.5 Alpha 1. This build includes all the fixes that are made to stable 4.4 version as well as two brand new data providers: Firebird 2.x & MySql 5.x, thanks to Csaba Beer & Malisa Ncube (thunderous applause here!).
As it is alpha, there are some limitations, such as: - Upgrade doesn't work yet in most scenarios for both Firebird & MySql. Hence, use 'Recreate' to update the database schema. Examples of ConnectionUrls/ConnectionStrings for these 2 providers are like the following: // MySql var connectionUrl = @"mysql://user:password@myserver:3306/database"; // Firebird var provider = "firebird"; var connectionString = @"User=user;Password=password;Database=C:\Program Files\Firebird\Firebird_2_5\database.fdb;DataSource=myserver; Port=3050;Dialect=3; Charset=NONE;Role=;Connection lifetime=15;Pooling=true; MinPoolSize=0;MaxPoolSize=50;Packet Size=8192;ServerType=0;"; // or var connectionUrl = @"firebird://user:password@myserver/C:\Program Files\Firebird\Firebird_2_5\database.fdb?Port=3050&Dialect=3&Charset=NONE&Role=&Connection lifetime=15&Pooling=true&MinPoolSize=0&MaxPoolSize=50&Packet Size=8192&ServerType=0"; The binaries are available at the corresponding section of Downloads page. Feedback of any kind is highly appreciated. Note: this is alpha version, it is not intended to be used in production.
Labels:
announcements,
community,
releases
Tuesday, April 12, 2011On security system, part 3
This is the third part in a series of posts that are dedicated to security system concept in DataObjects.Net. The first part contained common considerations and bits of theory, the second one was about the approach in development and the requirements to security system.
In this part I'll describe main blocks of security system architecture, i.e. roles & permissions. First of all, let's start with roles. As you might remember, there is a list of positions in our imaginary sales organization:
Role hierarchy for the imaginary sales company: Note, that each role is defined as a separate class. This approach as any other one has advantages and well as drawbacks. It is less dynamic, but provides natural inheritance, doesn't require persistence and is more intuitive, visual and understandable. Moreover, as roles in a company are mostly static, I've found the approach highly advantageous. Look, EmployeeRole inherits a Role class. This is the base role class, it provides inheritors with necessary infrastructure: a set of Permissions for a role, name of a role and a method for permission registration. To continue with roles hierarchy configuration we should define a permission first. According to the access matrix in the previous post, there are 2 common permissions that are actual for all kind of entities: Read permission & Write permission. In addition to these basic ones, there might be extended permissions as well, like Approve permission defined for Order entity type. Thus, we've defined a base Permission type and OrderPermission inheritor that provides requested functionality: Here is how EmployeeRole is declared: public class EmployeeRole : Role
{
public EmployeeRole()
{
// This is base role for every employee
// All employees can read products
RegisterPermission(new Permission<Product>());
// All employees can read employees
RegisterPermission(new Permission<Employee>());
}
}
That's it. Now all employees have a permission to read Products & Employees. What about the Stock manager role? Stock manager should inherit the base EmployeeRole and add permission for editing products. public class StockManagerRole : EmployeeRole
{
public StockManagerRole()
{
// Stock manager inherits Employee permissions
// Stock managers can read and edit products
RegisterPermission(new Permission<Product>(canWrite:true));
}
}
As I've already mentioned, the advantage of the class-based approach in role hierarchy definition is in its essential inheritance support. Derived role can inherit all permissions and other options of the base class and override something if is necessary. This is achievable in the most natural way for developers: make an inheritor & override all you need. On the other branch of roles hierarchy, Sales representative role also inherits the base EmployeeRole and should add permissions to edit customers and orders. In order to add Order permission we should define OrderPermission first, where a property CanApprove should be included. Here it is: public class OrderPermission : Permission<Order>
{
public bool CanApprove { get; private set; }
public OrderPermission(bool canWrite, bool canApprove)
: base(canWrite)
{
CanApprove = canApprove;
}
}
Having declared the OrderPermission, we can proceed with SaleRepresentativeRole class: public class SalesRepresentativeRole : EmployeeRole
{
public SalesRepresentativeRole()
{
// Sales representative inherits Employee permissions
// Sales representative can read and edit customers
RegisterPermission(new Permission<Customer>(canWrite:true));
// Sales representative can read and edit sale orders but not approve
RegisterPermission(new OrderPermission(canWrite:true, canApprove:false));
}
}
As for Sales manager role, it inherits Sales representative role and adds permission to approve orders. Here is how: public class SalesManagerRole : SalesRepresentativeRole
{
public SalesManagerRole()
{
// Sales manager inherits Sales representative permissions
// Sales manager can do sale orders approval, in addition
RegisterPermission(new OrderPermission(canWrite:true, canApprove:true));
}
}
The last one is Sales president role. It in turn has access to all entities in read-only mode plus write permission to Employees, so we have to override permissions declared in its ansector (SalesManagerRole): public class SalesPresidentRole : SalesManagerRole
{
public SalesPresidentRole()
{
// Sales president inherits Sales manager permissions
// Sales President can read all, but can't alter any details, except employees. They usually need read-only aggregated reports, actually
RegisterPermission(new Permission<Customer>());
RegisterPermission(new Permission<Order>());
RegisterPermission(new Permission<Product>());
RegisterPermission(new Permission<Employee>(canWrite:true));
}
}
Note the clarity and the ease of permissions overriding. That's all for today. For now we have permissions and roles defined. Hence, we've got a mechanism that can be used to describe the access matrix from the previous post in full manner:
Labels:
architecture,
security
Tuesday, April 05, 2011On security system, part 2
This is the second part in a series of posts that are dedicated to security system concept in DataObjects.Net. The first part contained common considerations and bits of theory.
In this part I'll tell you about the development approach we chose. To avoid the situation when a framework is being built according to some pure theoretical ideas and as a result it is hard to use it in real world scenarios we had decided to start from the other side: try implementing an application that seems to be more or less real, put into practice our security concepts and thus develop the security system. We chose Northwind database model as a playground and slightly modified it to add some complexity in company staff relationships. Here is the updated organization chart for our Northwind company. There are 2 sales departments: first is located in Seattle and second is in London. Both of them are managed by a sales manager, each of them has 2 sales representatives and 1 stock manager. Sales representatives report to sales manager, both sales managers report to sales president. In this application model we defined the following main types of entities to secure:
Next we have to define which company staff will have access to these secured entities, and which won't. Moreover, there might be several levels of access, for example, read, write and any other more specific ones. According to the organization chart, we define 4 main roles:
This matrix that demonstrates the additional limitations that must be met as well. So, here is the deal: we need to provide a flexible and efficient security framework that can be used in domain models like this one with all above-mentioned permissions and limitations. In the next post I'll show you whether we managed to achieve the goal and how we did it.
Labels:
architecture,
security
Monday, March 28, 2011DataObjects.Net Contribution Program Progress
Hi All,
As you might remember, in February Xtensive LLC officially announced the DataObjects.Net Contribution Program. Frankly speaking, we didn't even imagine what impressive results it would bring. First of all, I have to mention Csaba Beer and its efficient work on Firebird provider. Csaba developed Sql.Dom driver and now the entire Firebird provider is already integrated into DataObjects.Net ORM core (branch 4.5). It is being tested, fixed and polished by Xtensive LLC engineers. The alpha version will be available soon, may be even this week. Secondly, Malisa Ncube joined the Contribution Program and chose MySql provider as the goal. After several weeks of hard work the main part of Sql.Dom driver is almost finished. Today I've even managed to run all ORM tests on MySql. Unfortunately, not all of them finished successfully but that's OK for the first time. The work on the provider might require a week or two and after that it will be ready for the alpha. Last but not least, Entity Model Designer for DataObjects.Net that is being actively developed by Peter Ĺ ulek, appeared like a miracle for most of us. As you know, DataObjects.Net always was strictly code-centric tool and there were no designers or any other visual tools for it. But with the help of Peter the things have been principally changed to better side. While the tool itself is in alpha phase, it looks very promising. Peter promised to blog about the designer soon, so let's wait for the overview or tutorial. All of these brave and bright developers will receive DataObjects.Net Ultimate editions as a reward for their outstanding efforts. Wanna see yourself in the list? Choose a feature or two from the feature list and join da game! The reward is guaranteed.
Labels:
announcements,
community
Sunday, March 06, 2011Nightly builds are back
Hello All,
After some intense efforts of our developers the nightly builds are back and starting from this weekend are available on the downloads page. The first one (build #7299) is already published. Next builds will appear in the section on a regular basis as soon as fixes are applied to the codebase. The current technological process provides the ability to produce a fresh build within less an hour, so I am sure you will appreciate the innovation. There is still a couple of tasks that should be done to achieve better level of usability and transparency: for instance, a build should contain information about the changes that are made in it, so a visitor could get an idea which one he should download and install. Another exciting bit of news concerning nightly builds is that they will be available for everyone, not only for owners of Professional & Ultimate editions as it is stated on the prices page. The page will be updated soon to reflect this change. Thank all of you who use DataObjects.Net, who visit our support website, who report tricky bugs and request new awesome features. We are trying our best to deliver you mature and solid framework. Thanks for your choice.
Labels:
announcements,
website
Subscribe to:
Posts (Atom)
|
SubscriptionBlog Archive
Labels
|


















