Showing posts with label implement. Show all posts
Showing posts with label implement. Show all posts

Tuesday, March 27, 2012

Calculated Member banding

Hi,

I'm not sure if this is possible in analysis services or if i need to find dome other solution but i would like to implement a banding group on one of the measures in the analysis services cube i am developing.

I have a measue group counting visits and i can cross reference this with customers who are doing the visits. I'd like to be able to group customers in bands according to the amount of visits which they have done e.g.

300+ visits

200-299 visits

100-199 visits

<100 visits

Can this be done using a calculated measure or some other functionality within analysis services? If so can somebody suggest a solution.

All help is greatfully appreciated.

Cheers,

Grant

Hi,

I guess there is no nice and fast solution in cube.

Would you have a new dimension with the banding - or an attribute in the customer dimension or a seperate measure for the values?

I would recomend you add an column to your customer table and by ETL add the visits count. Based on this you could do a view or named query whith the band definition.

Other possible way is to add an datamining dimension with a cluster on the visits

Or do calculated mesasures for each band.

HANNES

|||

Thanks for the suggestions. I didn't think it was going to be a simple matter of doing this.

I don't think the value in the customer table will work too well in my case so i may look into a seperate dimension or calculated member for each band.

Your help is appreciated,

Grant

|||

Hi Again,

Sorry; this is probably a stupid question. How would i go about creating a seperate calculated measure for each banding group, what sort of format would it take?

Is it possible to create a calculated member consisting of a case statement which i could then use the results of the case statement to group measures on?

I may not be explaining this as well as i could but hopefully someone understands what i mean.

Many thanks,

Grant

|||

Hi,

from my perspective the calculation is the worst way because its the slowest and most complex and support the least flexibility I guess. I would not recomend if the cube is not small.

with calculation you could only create new measure for each band. I cannot create one measure and group by this.

The question as far as I remember - you need to have this band for each row in your fact data (leaf level at the cube) or for the customer on leaf only and all othere dimensions on the current node? (or root node?)

(if you need it on fact row level i would do it in the fact table query with a case .... - and use it as an fact dimension)

the calculation for customer only would be something like this

create member measures.customer100band;

scope(customer.key.members);

(measures.customer100band)=case when measure between x and y then measure else null end;

end scope;

This then uses the customer key and the current selection of all tothere dimensions for evaluation the formular. IT gets more dificult if you need this band not calculated by the current context.

Maybe someone else has a better solution for the calculation.

Best Regards

HANNES

|||

Thanks again for the response.

I'm having a little bit of a problem getting my head around what needs to be done. The problem initially is probably not completely understanding what i want to do. Taking your advice on board, i'll look into other methods aside from the calculated measure on the CustomerSite dimension. My fact table for visits has a default 1 column for basing the aggregation on so i cannot calculate in this table the bands.

If i have a seperate dimension; presumably this would consist of a key column and a column stating the band i.e.

Key Status

1 300+ visits

2 200 to 300 visits

.

.

.

etc...

The problem i have with getting my head around this method is where is link my dimension to; i cannot include the key in the fact table as i don't know at that stage how many visits are made to a specific customer for a selected date range. Do i not still need to link on the measure value that is returned at the chosen levels. I'm sorry if i'm not explaining this very well; this is a slightly steep learning curve at present.

Thanks again,

Grant

|||

As far as I understand you need your banding dependent on your selection (Time).

With this my calculation described above is the only method i would recommend.

As you already see - you cannot add by calculation new Attributes or Dimensions to the cube - cannot join your virtual dimension.

you only can create new members in existing dimensions / Attirubutes. Therefor you can only create new measures or new members in othere existing attributes.

Best Regards

HANNES

|||

I can see that adding a calculated member for each band will show the customers banding based on the selected date range. What i cannot see is how i would be able to slice the data based on the values in these bands. I don't see how i'd be able to get a count of customers for each of the visit bandings. Would this require another calculated member to work this out?

I'm starting to get to grips with this so thanks for your patience and help.

Grant

|||

Hi,

to slice and dice you need attributehierarchies in dimenions - with measure values associated to differnt members in this attributes.

Therefor you cannot slice and dice based on calculations (this is a singe member)

so you can do furthere calculations with your requirements or with one of my other sugestions.

Hannes

Calculated Member banding

Hi,

I'm not sure if this is possible in analysis services or if i need to find dome other solution but i would like to implement a banding group on one of the measures in the analysis services cube i am developing.

I have a measue group counting visits and i can cross reference this with customers who are doing the visits. I'd like to be able to group customers in bands according to the amount of visits which they have done e.g.

300+ visits

200-299 visits

100-199 visits

<100 visits

Can this be done using a calculated measure or some other functionality within analysis services? If so can somebody suggest a solution.

All help is greatfully appreciated.

Cheers,

Grant

Hi,

I guess there is no nice and fast solution in cube.

Would you have a new dimension with the banding - or an attribute in the customer dimension or a seperate measure for the values?

I would recomend you add an column to your customer table and by ETL add the visits count. Based on this you could do a view or named query whith the band definition.

Other possible way is to add an datamining dimension with a cluster on the visits

Or do calculated mesasures for each band.

HANNES

|||

Thanks for the suggestions. I didn't think it was going to be a simple matter of doing this.

I don't think the value in the customer table will work too well in my case so i may look into a seperate dimension or calculated member for each band.

Your help is appreciated,

Grant

|||

Hi Again,

Sorry; this is probably a stupid question. How would i go about creating a seperate calculated measure for each banding group, what sort of format would it take?

Is it possible to create a calculated member consisting of a case statement which i could then use the results of the case statement to group measures on?

I may not be explaining this as well as i could but hopefully someone understands what i mean.

Many thanks,

Grant

|||

Hi,

from my perspective the calculation is the worst way because its the slowest and most complex and support the least flexibility I guess. I would not recomend if the cube is not small.

with calculation you could only create new measure for each band. I cannot create one measure and group by this.

The question as far as I remember - you need to have this band for each row in your fact data (leaf level at the cube) or for the customer on leaf only and all othere dimensions on the current node? (or root node?)

(if you need it on fact row level i would do it in the fact table query with a case .... - and use it as an fact dimension)

the calculation for customer only would be something like this

create member measures.customer100band;

scope(customer.key.members);

(measures.customer100band)=case when measure between x and y then measure else null end;

end scope;

This then uses the customer key and the current selection of all tothere dimensions for evaluation the formular. IT gets more dificult if you need this band not calculated by the current context.

Maybe someone else has a better solution for the calculation.

Best Regards

HANNES

|||

Thanks again for the response.

I'm having a little bit of a problem getting my head around what needs to be done. The problem initially is probably not completely understanding what i want to do. Taking your advice on board, i'll look into other methods aside from the calculated measure on the CustomerSite dimension. My fact table for visits has a default 1 column for basing the aggregation on so i cannot calculate in this table the bands.

If i have a seperate dimension; presumably this would consist of a key column and a column stating the band i.e.

Key Status

1 300+ visits

2 200 to 300 visits

.

.

.

etc...

The problem i have with getting my head around this method is where is link my dimension to; i cannot include the key in the fact table as i don't know at that stage how many visits are made to a specific customer for a selected date range. Do i not still need to link on the measure value that is returned at the chosen levels. I'm sorry if i'm not explaining this very well; this is a slightly steep learning curve at present.

Thanks again,

Grant

|||

As far as I understand you need your banding dependent on your selection (Time).

With this my calculation described above is the only method i would recommend.

As you already see - you cannot add by calculation new Attributes or Dimensions to the cube - cannot join your virtual dimension.

you only can create new members in existing dimensions / Attirubutes. Therefor you can only create new measures or new members in othere existing attributes.

Best Regards

HANNES

|||

I can see that adding a calculated member for each band will show the customers banding based on the selected date range. What i cannot see is how i would be able to slice the data based on the values in these bands. I don't see how i'd be able to get a count of customers for each of the visit bandings. Would this require another calculated member to work this out?

I'm starting to get to grips with this so thanks for your patience and help.

Grant

|||

Hi,

to slice and dice you need attributehierarchies in dimenions - with measure values associated to differnt members in this attributes.

Therefor you cannot slice and dice based on calculations (this is a singe member)

so you can do furthere calculations with your requirements or with one of my other sugestions.

Hannes

sql

Tuesday, February 14, 2012

business vs. logic

You have seen a chair in a public room and go back after a while to acquire it. Is it unexpected that the object is not there anymore?

I implement the business logic in stored procedures. Once user orders some service, the actions carry out are: a)check they have sufficient funds on their balance; and, b) a price check is made selecting the latest from pricelist. The newly created job entry refers the price in the pricelist table according to service_id and the issued pricelist date.

These are data validity checks, which must be done in a multiuser database. In the session beginning, user gets prices and funds. These data are not locked throughout the session -- another process may change the records. Therefore, the extra "business" checks are needed to preserve data correctness at the start of every transaction. One way to report the errors would be to raise an error.

Consider the primary-foreign key violations. They are raised by system with severity level of 16. Uniqueness violation is raised with severity 14. The MSSQL reference http://msdn2.microsoft.com/en-us/library/ms164086.aspx tells us that this is a sort of error, which can be corrected by user. Indeed, (s)he can. But the exceptions are unexpected situations. Exception processing consumes huge CPU processing power if some occurs. Normally, programs allocate resources and use them. If resource cannot be allocated -- app exits with exception. It just has nothing to do. However, there is nothing exceptional in shared data access by multiple concurrent processes in a multithread/multiuser/distributed application. Since, we cannot lock the user resources during user session, we should be prepared to concurrent data changes. Therefore, I find the exception raising inappropriate tool.

Consider a situation, when one user is assigned to a group. Nothing prevents from another admin to remove the group at the same time. Therefore, our user management application should be ready to expected "group does not exist" "error" result. I even disagree that this is an error, since it is perfectly valid to have such a situation. It is like you have seen a chair in a room and later return to take it. But the chair is not there anymore. Is it unexpected? The case should not be exceptional, IMO.

So we have:
1. Severity 1-10 "informational messages";
2. Severity 11-16 errors; and
3. RETURN error_code.

Which should be used? Anything else? Do my considerations make sense?

When I want the SQL Code to with certainly 'talk' back to the application code, I use RAISERROR.

For SQL Procedures to 'talk' with each other, I may also use the RETURN value.

I may use 'WITH LOG' to force the error condition into the Application Log.

And you are wise to question what is an error condition. Is it a 'system' error, a 'logic' error, or a 'business rule' exception?

|||Thank you, Arnie for sharing your experience.


> And you are wise to question what is an error condition. Is it a 'system'
> error, a 'logic' error, or a 'business rule' exception?

I believe that the "business logic" is an oxymoron likewise "market order", which is chaos and disorder in fact. Nevertheless, I do not distinguish between "rules" and "logic" here. It is logical that user balance should not go below zero, it is logical that the price must be the latest one, it is logical that user must belong to an existing group.

I understand the exceptions in a serial programing where your threads allocate (lock) resources but not in distributed programing where you cannot be sure about current condition of resources. It is ok for the local copies of the data to be incoherent in multiprocessor system. When data become incoherent, they may cause logic/rules/constraint/etc violations.

Some recommend checking file existence before opening it. But another process may remove the file between the check and open op. System returns "file does not exist" open error. It does not investigate whether the thread checked the file existence or it is making a reckless open. In other words, it does not examine the intentions and conditions of the caller. One utility would, for instance, set up admin rights for a list of users. This 'setadmin' app assumes the group 'admins' exists. It has nothing to do if there is no such group. It is exceptional situation for the app. Another application requests available groups, uses one and sends result back. Multiuser application should be prepared to situation where the used group does not exist anymore. A more realistic is a stock with multiple operators. When you have selected the list of available goods into a local copy, the goods can be removed by another operator.
You should tell the user that the product list is outdated, that it is incoherent with reality rather than complaining that the operation cannot be accomplished.

Looks like, error handling in distributed systems is more general than a DB errors issue. But any advices are welcomed.
|||

Valentin,

Note that I didn't use the term 'business logic', but instead used 'business rule exception' -and yet I agree with you that often business needs sometimes seem to defy logic; and that when describing the condition of a market, 'market order' could easily be a oxymoron, but when used as a entity, 'market order' has a definitive 'thing' quality about it.

This, and your other posts on Locking behavior demonstrate a deep concern for data integrity, and I can certainly appreciate your questions. When there are opportunities for instability, instability will occur. Stasis can only exist when ignoring temporality. Yet, in fact, Stasis cannot be separated from temporal considerations. The certainity of a state of data is increasingly uncertain as the system becomes more complex -distributed, multiprocessor, and multi-threaded. We often resort to extreme control when faced with apparant chaos. As TS Elliot would describe it, the time 'between' is the shadow, and we cannot ignore the shadow, for all things unknown exists in the shadow.

I once worked on a project where, for speed, data was cached on each web server in a very large web farm, and yet many data items were unique and ONLY one customer would be allowed to purchase that one item. There could be thousands of concurrent customers considering the same item. It was necessary to create a lot of communication between the cach objects, tenative 'sold' indicators, and definitive 'sold' indicators, 'cancellation', etc. You can imagine the chaos -but it did have a solution.

Since, as you put it so well, there are opportunities for chaos between the moment we determine IF an action can be taken AND the moment the action is actually taken, AND the 'system' doesn't help 'protect' us from that potential chaos, we are faced with having to find ways to invoke 'extreme control'. So like forcing all passengers through the security checkpoint as a single point of control, it may be useful to consider how to force all sensitive data activity through a 'single point of control'.

One useful approach is to force all data changes through Stored Procedures (No direct table access). Then in the Stored Procedure used to UPDATE a set of resouces in a TRANSACTION, also use sp_getapplock / sp_releaseapplock as a way to more tightly control access to the resources.

Here is an example: (Use Northwind database)

Code Snippet


CREATE PROCEDURE dbo.Employees_U_LastName
( @.EmployeeID int,
@.LastName varchar(20)
)
AS
BEGIN
SET TRANSACTION ISOLATION LEVEL REPEATABLE READ
BEGIN TRANSACTION


DECLARE @.LockResult int

EXECUTE @.LockResult = sp_getapplock
@.Resource = 'ThisIsMyProcess-StayOut',
@.LockMode = 'Exclusive',
@.LockTimeout = 0

IF @.LockResult <> 0
BEGIN
ROLLBACK TRANSACTION
PRINT 'SomeOne Else is Using this Resource'
RETURN
END


PRINT 'TRANSACTION IS Active'
SELECT
EmployeeID,
LastName,
FirstName
FROM Employees
WHERE EmployeeID = @.EmployeeID


PRINT 'Waiting...'
WAITFOR DELAY '00:00:15'

PRINT 'Second UPDATE to Active TRANSACTION'
UPDATE Employees
SET LastName = @.LastName
WHERE EmployeeID = @.EmployeeID


EXECUTE sp_releaseapplock
@.Resource = 'ThisIsMyProcess-StayOut'


COMMIT TRANSACTION


PRINT 'Waiting for Other Process to Complete'
WAITFOR DELAY '00:00:05'

PRINT 'CHECK Results of TRANSACTION'
SELECT
EmployeeID,
LastName,
FirstName
FROM Employees
WHERE EmployeeID = @.EmployeeID


END
GO

Then execute this from two different connections.

Code Snippet


EXECUTE dbo.Employees_U_LastName
@.EmployeeID = 1,
@.LastName = 'Davolio-Jones'

In the second connection, you will get the message: 'SomeOne Else is Using this Resource'. But you have to be adamant that there is only one 'egress' point to the resources -through the procedure.

Perhaps this will help you along on your quest to find a secure and reliable method to control data

|||

Sometimes maybe it doesn't matter if the 'problem' is a 'system' error, a 'logic' error, or a 'business rule' error -the 'problem' has to be handled, and in the case at hand, they may all be handled the same. It is still very useful to keep clarity about the differences between them. For at times, the effect of treating them the 'same' is confusing at best.

valentin tihomirov wrote:

I do not distinguish between "rules" and "logic" here. It is logical that user balance should not go below zero, it is logical that the price must be the latest one, it is logical that user must belong to an existing group.

Logic follows defined mathematical sylogisms.

1 = 2

2 = 3

Therefore 3 = 1

is based on logic. That balance MUST be >= 0 is a Business decision (busines rule) solely BECAUSE [ bal < 0 ] is mathematically valid -but in this situation, this business has determined to not allow that to occur. A bank 'should' not allow an account to overdraw (balance >= 0 ) at all times, in other words, as the trustee for your money, the bank 'should' not give others money claiming that it is your money if you don't have money to give out. However, the banking industry decided that there was money to be earned by allowing overdrafts, and you can't charge for an overdraft UNLESS the balance is allowed to be less than zero, so the business rule changed, and balance can be less than zero ( to some limit ).

Logic is easy to code, business rules, subject to change, require a lot more effort and consideration.

Of course, I realize that you know what I'm talking about. I'm using your posting to help others that may be reading, and still learning, and still uncertain... (So I hope you accept the 'lecture' in that guise. I often respond to a posting with the realization that I may also be responding to other readers with similar -but not exactly the same, questions.)

|||

For clarification, in the demonstration procedure I posted earlier, I used a PRINT statement when checking if @.LockResult. Normally, I would raise an error so that the calling application (or procedure) can capture the error number and react accordingly.

First, create the Error in the database, (Use whatever Error Number ( > 50000 ) and message you wish.)

Code Snippet

EXECUTE sp_addmessage
@.msgnum = 51001,
@.severity = 16,
@.msgtext = N'Resource NOT Available',
@.lang = 'us_english',
@.replace = REPLACE

Then in the procedure:

Code Snippet

IF @.LockResult <> 0
BEGIN
ROLLBACK TRANSACTION
RAISERROR ( 51001, 16, 1 )
RETURN
END

Now the application (or calling procedure) can handle ErrorNumber 51001 as deemed necessary. Wait a few seconds and Re-Submit perhaps...

|||

Arnie Rowland wrote:

One useful approach is to force all data changes through Stored Procedures (No direct table access).

SPs are really how I'm trying to do it. Thanks for hinting about sp_getapplock. It looks like a 'lock' object (mutex, critical section) in conventional programming language. However, I think it is too coarse-grain. All the users who wish to change their last names will lock each other. In addition, this lock shell be taken by parties who affect the last names in different way (removing the record, for instance). And you get the whole database locked/synchronized by one big lock. The granularity of automatic transactional locks are one record. However, using full db object names like db_name.table_1.row_id.field_x we can outperform the locking granularity down to field finesse. These are my first ideas about the procedure. Thanks for the hint.

Arnie Rowland wrote:

Logic follows defined mathematical sylogisms.

I was learnt it is the math, which is a science of proving, which is based on logic But I think I can understand the difference between logic and rules now. Thank you for the explanation.

Arnie Rowland wrote:

Of course, I realize that you know what I'm talking about. I'm using your posting to help others that may be reading, and still learning, and still uncertain... (So I hope you accept the 'lecture' in that guise. I often respond to a posting with the realization that I may also be responding to other readers with similar -but not exactly the same, questions.)


That is ok, I am a communist. The sharing is a means of saving resources and a condition of intelligent life survival on the planet Earth.

|||

You're right, using sp_getapplock is kind of 'course-grained'; sp_getapplock creates a 'lock' object, using the name you provide. The only thing 'locked' is the entry to the sproc code. The included (and required) TRANSACTION locks the underlying data. However, blocking others from using the sproc code in practice creates a single 'gateway' through which all controlled activity must pass, effectively forcing serialization of the controlled activity. I would want to make the process as streamlined and efficient as possible in order to cause the minimal amount of queue stacking.

In a very high performance / high utilitzation system, using sp_getapplock just may prove to be to much of a 'bottleneck'. But, if one was concerned about reading into an active TRANSACTION, and the effects on other activities as a result of being able to read into an active TRANSACTION, sp_getapplock is one way to reduce the 'paranoia'. It may be too 'heavy-handed' for most use.

...deleted...

Keep up the good questions.

Business Objects vs. Analysis Services and IT Bullies

Hello,

I've been working on implementing an SSAS solution for my department. The Proof of Concept is working very well and I am ready to implement it. However, some bullies from IT have come in and said that cubes are not the correct way to go about this (even though it is working) and that we need to call Business Objects and have them come in and tell us what they can provide.

To create my solution, I am using SSIS, SSRS, and SSAS. It is a great package that has everything in it and, frankly, I don't want to have to redo all my work.

When Business Solutions comes in I want to be able to ask them questions (objectively and fairly) about what they can provide us. If they have a better solution, then I should take it, but if it is sort of borderline, I want to be able to "win" with Microsoft and SQL Server 2005. One quick example that I know of is that when sending a report from Business Objects to Excel, the format is not always pretty and/or easy to deal with.

Any suggestions about a comparison list or feature by feature list of the two? Or maybe just some pointed questions about can Business Objects do X? Maybe questions about speed, stability, "plays well with others (Oracle)", etc.

Thank you for the help.

-Gumbatman

Hello! Here is my list:

Does BO have their own relational database and ETL tool?

Why should you pay for BO when you have SSAS, SSRS, SSIS, SQL Server 2005 bundled and without extra license cost?|||

Hi,

I implemeted a DW project last year, using SSIS then both Business Objects and SSAS on top of that. Have to say that the amount of time spent developing the BO universe and reports took almost as long as the ETL process (generally reporting times are far shorter).

From a support and development aspect, the extra level of design which is built into BO is a nightmare to support. You will end up needing people who are experts in both SQL and BO, not many, and those are all probably contracting.

Did notice that if your reports get complicated or the BO Universe does magical things, the performance hit was on the SQL Database. If the database is a transactional one rather than a DW you could encounter problems with performance. I don't think it has quite the same query performance as SSAS, although BO could do some very clever things that SSAS couldn't or would be very difficult to do (more in business modelling).

It also depends how many people are using the reports, more users probably more hits on the underlying database; I don't think there is any caching like in SSAS, so if someone runs the same report it will have to query the database again rather than hit the cache.

Don't think there are aggregations in BO, we didn't use any. Think we create table functions to aggregate things up to differnt levels of granularity.

In my opinion if you have a BO team in the company, it is a route you could use as well as SSAS. Allows you to migrate away from BO into a SSAS world..

The improvements of Excel 2007, reporting services in 2008 and proclarity all make BO look basic and dated.

Sure if you contact Microsoft and asked them the question, they would list a load of things. Probably have a fact file on the matter.

Sorry for the long reply!

Hope that helps

Matt

|||

Matt and Thomas,

Thank you for the answers. This is great information and will go a long way for me.

-Gumbatman

Business Objects vs. Analysis Services and IT Bullies

Hello,

I've been working on implementing an SSAS solution for my department. The Proof of Concept is working very well and I am ready to implement it. However, some bullies from IT have come in and said that cubes are not the correct way to go about this (even though it is working) and that we need to call Business Objects and have them come in and tell us what they can provide.

To create my solution, I am using SSIS, SSRS, and SSAS. It is a great package that has everything in it and, frankly, I don't want to have to redo all my work.

When Business Solutions comes in I want to be able to ask them questions (objectively and fairly) about what they can provide us. If they have a better solution, then I should take it, but if it is sort of borderline, I want to be able to "win" with Microsoft and SQL Server 2005. One quick example that I know of is that when sending a report from Business Objects to Excel, the format is not always pretty and/or easy to deal with.

Any suggestions about a comparison list or feature by feature list of the two? Or maybe just some pointed questions about can Business Objects do X? Maybe questions about speed, stability, "plays well with others (Oracle)", etc.

Thank you for the help.

-Gumbatman

Hello! Here is my list:

Does BO have their own relational database and ETL tool?

Why should you pay for BO when you have SSAS, SSRS, SSIS, SQL Server 2005 bundled and without extra license cost?|||

Hi,

I implemeted a DW project last year, using SSIS then both Business Objects and SSAS on top of that. Have to say that the amount of time spent developing the BO universe and reports took almost as long as the ETL process (generally reporting times are far shorter).

From a support and development aspect, the extra level of design which is built into BO is a nightmare to support. You will end up needing people who are experts in both SQL and BO, not many, and those are all probably contracting.

Did notice that if your reports get complicated or the BO Universe does magical things, the performance hit was on the SQL Database. If the database is a transactional one rather than a DW you could encounter problems with performance. I don't think it has quite the same query performance as SSAS, although BO could do some very clever things that SSAS couldn't or would be very difficult to do (more in business modelling).

It also depends how many people are using the reports, more users probably more hits on the underlying database; I don't think there is any caching like in SSAS, so if someone runs the same report it will have to query the database again rather than hit the cache.

Don't think there are aggregations in BO, we didn't use any. Think we create table functions to aggregate things up to differnt levels of granularity.

In my opinion if you have a BO team in the company, it is a route you could use as well as SSAS. Allows you to migrate away from BO into a SSAS world..

The improvements of Excel 2007, reporting services in 2008 and proclarity all make BO look basic and dated.

Sure if you contact Microsoft and asked them the question, they would list a load of things. Probably have a fact file on the matter.

Sorry for the long reply!

Hope that helps

Matt

|||

Matt and Thomas,

Thank you for the answers. This is great information and will go a long way for me.

-Gumbatman

Business Logic Handler Not Loading

I'm trying to implement a custom conflict resolver by inheriting from

Microsoft.SqlServer.Replication.BusinessLogicSupport.BusinessLogicModule. The replication is between a SQL Server 2005 Express subscriber and a SQL Server 2005 publisher/distributer.

The problem is that the resolver class in the DLL will not load; although, it does appear to find the DLL. (If I rename the DLL I get a "file not found error"). The exact error message is:

Microsoft.SqlServer.Replication.ComErrorException

"Error loading custom class "MergeConflictHandler" from custom assembly "MergeConflictHandler",

Error : "Could not load type 'MergeConflictHandler' from assembly 'MergeConflictHandler, Version=1.0.2502.22393, Culture=neutral, PublicKeyToken=0403e50cc4dc27fa'."."}

I placed the DLL in the directory of the program that calls SynchronizationAgent.Synchronize and tried it with and without being registered in the GAC. There was no change. Interestingly, when I move the file out of that location, but register it in the GAC, the file is not found. Thinking it may be a security problem, I gave Everyone Read & Execute and Read privileges. I believe the class is actually instantiated by replmerge.exe, an apparantly unmanaged app, so I tried marking it ComVisible. No Luck.

I registered the resolver with the following T-SQL code:

sp_registercustomresolver @.article_resolver = 'eClinical Notes Conflict Resolver'

, @.is_dotnet_assembly = 'true'

, @.dotnet_assembly_name = 'MergeConflictHandler'

, @.dotnet_class_name = 'MergeConflictHandler'

, @.resolver_clsid = Null

The resolver I've created is not much more than a shell at this point. It is pasted below, but I tried using the code found on MSDN character-for-character and had the same problem.

using System;

using System.Text;

using System.Data;

using System.Data.Common;

using Microsoft.SqlServer.Replication.BusinessLogicSupport;

namespace MergeConflictHandler

{

public class MergeConflictHandler :

Microsoft.SqlServer.Replication.BusinessLogicSupport.BusinessLogicModule

{

// Variables to hold server names.

private string m_PublisherName;

private string m_SubscriberName;

private string m_Artical_Name;

public MergeConflictHandler()

{

}

// Implement the Initialize method to get publication

// and subscription information.

public override void Initialize(string publisher, string subscriber, string distributor, string publisherDB, string subscriberDB,string articleName)

{

m_PublisherName = publisher;

m_SubscriberName = subscriber;

m_Artical_Name = articleName;

}

// Declare what types of row changes, conflicts, or errors to handle.

public override ChangeStates HandledChangeStates

{

get

{

return ChangeStates.UpdateConflicts;

}

}

public override ActionOnUpdateConflict UpdateConflictsHandler(DataSet publisherDataSet, DataSet subscriberDataSet, ref DataSet customDataSet, ref ConflictLogType conflictLogType, ref string customConflictMessage, ref int historyLogLevel, ref string historyLogMessage)

{

if (m_Artical_Name == "PatientAllergies")

{

// Accept the updated data in the Subscriber's data set and apply it to the Publisher.

}

return ActionOnUpdateConflict.AcceptPublisherData;

}

}

}

Does anyone have any thoughts or advice? (Help!)

I had similar problems

I found that the parameter @.dotnet_class_name had to be set to assemblyName.className

If in your case the assembly is named the same as the class then it would need to be set to MergeConflictHandler.MergeConflictHandler

|||

Aero1 Thanks So Much

It is now working, although not exactly as you said. Apparantly the @.dot_class_name parameter needs to be prefixed with the Namespace, not the assemblyName. Perhaps your name space and assemblyName were the same for you? Anyway, I had tried prefixing the Namespace before, but obviously I did something wrong then. As an added benefit, it makes sense. Of course it still should be better documented! So to highlight the answer for future readers:

@.dot_class_name = 'Namespace.Classname'

Thanks again... Life is once again worth living.

|||

This is documented in: http://msdn2.microsoft.com/zh-cn/library/ms147911.aspx

However we will try to make it more discoverable.