SSDT Schema Compare always adding objects, which are "Build = None" in Solution - sql-server

In my Visual Studio Database Solution, I have some objects, which I had to set Build action = None, due to several reasons (Problems in build caused by OPENQUERY,...).
Unfortunately the Schema Compare doesn't compare those elements. Whenever i do a compare "source = development DB" & "target = solution", they are marked as new and schema compare will suggest to add those objects.
If i add those objects, the update will recognize, that they're already in the solution and will add the elements with a new name [objectname]+_1 and Build action = Build , which will of course cause problems during the next build.
Does anybody know if there is an easy way around this problem? Except working with Pre-build and Post-Build command line, to disable objects before building and enable them after building again.
Thanks in advance

Minimal reproducible example as requested in comment:
SebTHU: Adding minimal reproducible example.
Create a new, empty sandbox database.
In the database, run this script:
CREATE TABLE Table1(PersonID INT NOT NULL,FullNam nvarchar(255) NOT NULL) GO CREATE TABLE Table1_New (PersonID INT NOT NULL,FullName nvarchar(255) NOT NULL) GO CREATE VIEW vwOriginalView AS SELECT PersonID,FullNam FROM Table1 GO EXEC sp_rename 'Table1','ZZZTable1','OBJECT' GO EXEC sp_rename 'Table1_New','Table1','OBJECT' GO CREATE VIEW vwNewView AS SELECT PersonID,FullName FROM Table1 GO
This simulates an effective ALTER TABLE on Table1, but with the original table being retained as a renamed deprecated object. vwOriginalView now has an invalid reference, but we want to retain it (for the moment) as well; it would be renamed, but that's not necessary to demonstrate this problem.
In VS, create a new Database Project.
Run Schema Compare against the sandbox database. Press Update to add scripts for the 4 objects into the project. Keep the comparison window open.
There are now build errors (vwOriginalView has an invalid reference to column Fullnam). To ignore this object, set its BuildAction to None. The errors disappear.
Press Compare on the comparison window again. vwOriginalView now appears as a "new" object in the DB, to be added to the project.
This is the problem. It's nice to be reminded that, if it does exist in the project, the object's BuildAction is set to None. But with many (20-30) objects of this kind, SchemaCompare becomes confusing.
What I need is either a way for Compare to treat "BuildAction=None" objects as existing objects in the project - ideally switchable as an option, so that these objects can be made clearly visible in Compare if needed; or a way to make deprecated objects (specifically, my choice of objects) not cause build errors - an alternative to "BuildAction=None".
I've tried SQL error suppression in VS, but for one thing it doesn't work, and for another suppressing these kind of errors globally would be a bad idea.

Related

Find functions using temp tables where NVARCHAR limit does not match its referenced table definition

Problem: Junior SQL dev here, working with a SQL Server database where we have many functions that use temp tables to pull data from various tables to populate Crystal reports etc. We had an issue where a user action in our client caused a string to overflow the defined NVARCHAR(100) character limit of the column. As a quick fix, one of our seniors decided on a schema change to set the column definition to NVARCHAR(255), instead of fixing the issue of the the string getting too long. Now, we have lots of these table based functions that are using temp tables referencing the column in question but the temp table variable is defined as 100 instead of 255.
Question: Is there an easy way to find and update all of these functions? Some functions might not reference the table/column in question at all, but some heavily rely on this data to feed reports etc. I know I can right click a table and select "View Dependencies" in SQL Server Management Studio, but this seems very tedious to have to go through all of them and then update our master schema before deploying it to all customers.
I thought about a find and replace if there is a way to script or export the functions but I fear a problem I will run into is one variable in one function might be declared as TransItemDescription NVARCHAR(100) and one might be TransItemDesc NVARCHAR (100). I've heard of people avoiding temp tables maybe because of these issues so maybe there is just bad database design here?
Thus far I've been going through them one at a time using "View Dependencies" in SSMS.
I think the best solution would be to script out the whole database into a single script from SSMS. Then use Notepad++ (or equivalent) to either find:
All occurrences of NVARCHAR(100)
All occurrences of the variable name, e.g. TransItemDescription, TransItemDesc.
Once you have found all occurrences then make a list of all of the functions to be fixed. Then you would still need to do a manual fix to all functions, but once complete the issue should be totally resolved.

SSDT has an unresolved reference to object for views but works fine for procedure

This error is not the "normal error", when there is a missing database reference. I have a database reference added correctly, and it worked fine so far with stored procedures.
The problem:
I have a database project, let's call it BIDK. This database has a reference to dacpac file, build from a nother database project called RPTDK.
RPTDK has a table called dbo.BILLINGITEM, which I can reference from BIDK database project using this code:
create proc CommonDM.TestReferenceFromProc
as
select BILLINGITEM_ID,
TIMESTAMP,
BILLINGITEMTYPE_ENUMID,
VATCODE_ENUMID,
LCOMPANY_ID,
LEASESERVICECOMPONENT_ID
from [RPTDK].[dbo].BILLINGITEM as bilitm;
This works fine, and I can build the project BIDK. Shiny Happy Poeple Dancing!
However, if I add this view, then the build fails:
create view CommonDM.TestReferenceFromView
as
select BILLINGITEM_ID,
TIMESTAMP,
BILLINGITEMTYPE_ENUMID,
VATCODE_ENUMID,
LCOMPANY_ID,
LEASESERVICECOMPONENT_ID
from [RPTDK].[dbo].BILLINGITEM as bilitm
I cannot build the project BIDK with the view added, and I get the error message:
[CommonDM].[TestReferenceFromView] has an unresolved reference to object [RPTDK].[dbo].[BILLINGITEM]
Any idea why this is happening?
Why is it working for stored proc and not for views?
I had a case like this before, instead of specifying database name, try to select without specifying the database name like this
select BILLINGITEM_ID,
TIMESTAMP,
BILLINGITEMTYPE_ENUMID,
VATCODE_ENUMID,
LCOMPANY_ID,
LEASESERVICECOMPONENT_ID
from [dbo].BILLINGITEM
or using [$DBName] for the database name like this
select BILLINGITEM_ID,
TIMESTAMP,
BILLINGITEMTYPE_ENUMID,
VATCODE_ENUMID,
LCOMPANY_ID,
LEASESERVICECOMPONENT_ID
from [$RPTDK].[dbo].BILLINGITEM as bilitm
it worked for me
After testing and trying different settings, I can conclude that the "correct" approach is to use the [$(RPTDK)] syntax, where the RPTDK is the name that of the parameter, as it is set when one adds the database reference to begin with.
select BILLINGITEM_ID,
TIMESTAMP,
BILLINGITEMTYPE_ENUMID,
VATCODE_ENUMID,
LCOMPANY_ID,
LEASESERVICECOMPONENT_ID
from [$(RPTDK)].[dbo].BILLINGITEM as bilitm
It is a bit annoying, and the code is now dependent on a SQLCMD mode parameter to work, when you want to copy and paste into a SSMS window.
Thanks Alfin for the assistance.
ps
The reason why this is not failing in a stored proc, is that it seems to be that Visual Studio SSDT is not checking for referenced objects in a stored proc, but does it for views. I tried to remove the reference all togetger, and the stored proc code still managed to build succesfully.
To be short - SSDT likes 2-part names. You can use variables for 3-4 part names, but ideally you should create either dacpac or project for each external database. Then reference them in your main project. Then for every external object you need to create synonyms and then you'll not have more problems. Moreover it will give you possibility to have different databases/instances names on different environments.
You can find an example how to organize the solution with SSDT in my github repo. I still want to add some more stuff there, but you can see an example how to work with it for your case.
I know this is an old thread, and I don't have enough reputation to add a comment to the correct answer above, but I wanted to supply a detail to the answer so I'm entering it as an 'answer'.
The reason stored procedures with unknown references (as opposed to views) cannot be flagged as errors by the SSDT reference checker is that stored procedures are dynamic and can affect the schema during execution.
In other words, a proc could reference TableA which does not exist when the project is deployed, but the proc could dynamically create TableA before it needs to use it. If SSDT flagged the unknown reference as an error, you could never build the project and never deploy it.

Set schema name in SqlUserDefinedTypeAttribute

When creating a UserDefinedType in C# code for the sake of SQLCLR integration, it is required that you prefix a class or struct with a SqlUserDefinedType, such as here:
[SqlUserDefinedType(
Name = "g.Options",
// ...
)]
public struct Options : INullable {
// ...
}
Notice that in the "Name" parameter, I attempt to set a schema in addition to the object name. But, when I generate the script in the publish stage of a Visual Studio Database Project, I get:
CREATE TYPE [dbo].[g.Options]
There is no "schema" parameter for SqlUserDefinedType.
I do believe I can write the T-SQL script to make the type from the assembly specifically, but I would like to avoid that, as I plan on putting most of my types in different schemas and wouldn't be happy to have to register via explicit TSQL on each one.
EDIT:
As Solomon Rutzky points out, you can set the Default Schema in the project properties. It is certainly no substitute for something akin to a 'schema' parameter in SqlUserDefinedType, particularly if you want to work with multiple schemas, but it certainly gets the job done for many people's needs.
A post-deployment script will technically get the job done, but unfortunately, the comparison engine doesn't know about the post-deployment logic and so will perpetually register the schema difference as something that needs to be changed. So all your affected objects will be dropped and re-created on every publish regardless of whether you changed them or not.
The Schema name is specified in a singular location per each project, not per object.
You can set it in Visual Studio via:
"Project" (menu) -> "{project_name} Properties..." (menu option) -> "Project Settings" (tab)
On the right side, in the "General" section, there is a text field for "Default schema:"
OR:
you can manually edit your {project_name}.sqlproj file, and in one of the top <PropertyGroup> elements (one that does not have a "Condition" attribute; the first such element is typically used), you can create (or update if it already exists) the following element:
<DefaultSchema>dbo</DefaultSchema>
HOWEVER, if you are wanting to set one object (such as a UDT) to a different Schema name than the rest of the objects are using, that would have to be done manually in a Post Release SQL script. You can add a SQL script to your project, then in the Solution Explorer on the right side, select the SQL script, go to its Properties, and for "BuildAction", select "PostDeploy". In that post-deploy script, issue an ALTER SCHEMA statement:
ALTER SCHEMA [g] TRANSFER TYPE::dbo.Options;

Using Effort (EF Testing Tool) with Computed Column

I have a number of integration tests which access the DB directly - create test prerequisite objects - performs the tests and then cleans up afterwards - however I wonted to try out the same approach in-memory.
I have just used Effort in my project and it works very easily. However I've hit a problem that I have been trying - but unable to solve.
One of the tables that I need filled up with dummy data - as a test prerequisite - contains a computed column (nvarchar, not null). For the scope of the test I really don't care about that column's value - but even if I try to insert dummy data, my data is ignored and then I get hit with an error:
"Column 'x' cannot be null. Error code: GenericError"
In my tests I am using the same edmx file as is used by the actual code. This prevents me from constantly updating the edmx copy.
Is there a way in which I can force the test to update the edmx (at runtime) so that column is a nullable non-computed column? [overriding OnModelCreating] or is there way to insert a default value (anything goes for this column) to stop this error? [overriding SaveChanges]
I have currently tried the following:
Attaching the objects using .Attach() instead of .Add()
Setting the EntityState to Unchanged after adding
Forcing the value through Entry.OriginalValues [this values since entity is in Added state]
Edit:
I have tried overriding the OnModelCreating method, but to no avail since this is DB-First.
modelBuilder.Entity<Entity_Name>().Property(p => p.x).IsOptional().HasDatabaseGeneratedOption(System.ComponentModel.DataAnnotations.Schema.DatabaseGeneratedOption.None);
Open your EDMX file in XML editor, find your entity under the StorageModels,
and add to the column definition StoreGeneratedPattern="Computed".
But if you update or delete and add that table you will loose this modification. Actually you can write console app that will update you edmx file and add StoreGeneratedPattern="Computed" where needed and you can add those app to prebuild events in studio.
The reason of the problem was a bug in the Effort database. When the computed column is based on non-nullable columns, the computed column would also automatically become non-nullable. Therefor, the Effort database was expecting a non-null value. With the latest update the problem is resolved. You have to set the global EntityFrameworkEffortManager.UseDefaultForNotNullable flag as true.
See the issue on github

VS 2012 Database Project "unresolved reference to object" Error

I created SQL Server Database Project in VS 2012 & imported our database.
When I build the project, I get a lot of "unresolved reference to object" Errors.
These errors are only for a few views I have in my database.
The syntax for these views are correct & I am not using temp tables.
What should I check to solve this issue?
UPDATE:
This is one example:
CREATE view [Factory].[NonStartedOrders]
as
SELECT
"Customers"."CustomerName", "Customers"."CustomerAName",
"Customers"."MarketID",
"Orders"."OrderID",
"Orders"."ApproveDate",
"FactoryOrders"."FactoryID",
"FactoryOrders"."EstEndDate",
"FactoryOrders"."StatusID",
"FactoryOrders"."TotalWeight",
"Karats"."KaratEName"
FROM (("Taiba"."Sales"."FactoryOrders" "FactoryOrders"
INNER JOIN "Taiba"."Sales"."Orders" "Orders" ON "FactoryOrders"."OrderID"="Orders"."OrderID")
INNER JOIN "Taiba"."General"."Customers" "Customers" ON "Orders"."CustomerID"="Customers"."CustomerID")
INNER JOIN "Taiba"."MasterPiece"."Karats" "Karats" ON "Orders"."MKaratID"="Karats"."KaratID"
"Taiba" here is my database name.
I am getting 30 errors only for this view.
These are a few errors of them:
Error 217 SQL71561: View: [Factory].[NonStartedOrders] has an unresolved reference to object [Taiba].[Sales].[FactoryOrders]
Error 219 SQL71561: View: [Factory].[NonStartedOrders] contains an unresolved reference to an object. Either the object does not exist or the reference is ambiguous because it could refer to any of the following objects: [Taiba].[Sales].[FactoryOrders].[FactoryOrders]::[OrderID], [Taiba].[Sales].[FactoryOrders].[OrderID] or [Taiba].[Sales].[Orders].[FactoryOrders]::[OrderID].
One other possibility is that the schema you have used in your view/table etc does not exist in the project. You may need to add the schema to the VS Database Project.
Right Click the project and Add > New Item > Schema
I solved this issue.
It seems a few of my views/SPs have referenced the tables using this naming convention ( 3 parts qualified name ):
DatabaseName.SchemaName.TableName
I changed all references to be as the following:
SchemaName.TableName
In my case, the function that couldn't be found was of Build Action=None and so it wasn't being included in the compile.
Changing the Build Action to Build corrected this.
This happened to me when building a CTE in Visual Studio 2015. I changed the Build Action to Compile and the errors went away.
Select the file(s) with the error
Press F4 to see the properties.
Select 'Compile' in the Build Action drop down list.
Hope this helps someone.
To reference another sqlproj's schema and use three-part naming, modify your .sqlproj file to add a DatabaseVariableLiteralValue element on the referenced project.
In within the element like
<ProjectReference Include="..\SomeDatabaseProject\SomeDatabaseProject.sqlproj">, add the following:
<DatabaseVariableLiteralValue>SomeDatabaseProject</DatabaseVariableLiteralValue>
For example:
<ProjectReference Include="..\SomeDatabaseProject\SomeDatabaseProject.sqlproj">
<Name>SomeDatabaseProject</Name>
<Project>{some-project-guid}</Project>
<Private>True</Private>
<DatabaseVariableLiteralValue>SomeDatabaseProject</DatabaseVariableLiteralValue>
</ProjectReference>
Then you can use clean, three-part naming references like SomeDatabaseProject.SomeSchema.SomeTable.
It is possible that the objects are inside NotInBuild tag in the project file for naming or other issue. In my case I saved the file with ..sql and the extra dot was causing it to move under NotInBuild tag inside project file. I corrected the extension and moved the missing object under build tag and that resolved the issue.
Try explicitly defining the class:
class: Specifies the class of the securable on which the permission is being
granted. The scope qualifier :: is required.
Read the docs on the SQL GRANT statement: http://technet.microsoft.com/en-us/library/ms187965.aspx
In my case I had a User Defined Table Type.
GRANT EXECUTE ON TYPE::[dbo].[MessageTableType] TO [PostOffice_Role];
You will also get this error when you add a table (using .sql file ) and if you do not check-in the .sqlproj file
This may be an edge case but if in your object definition you are also documenting the object (we do, anyway...) using sp_addextendedproperty you can also get this error if you have stated an incorrect object type - which can happen if copy & pasting. The "unresolved reference to object" error makes sense here when you think about it.
For example the following will recreate the error as the level1type should be 'PROCEDURE' and not 'FUNCTION'.
EXEC sp_addextendedproperty
#name = N'MS_Description',
#value = N'Description of the stored procedure...',
#level0type = N'SCHEMA',
#level0name = N'dbo',
#level1type = FUNCTION',
#level1name = N'spMyStoredProcedureName'
GO
I have a DacPac project containing objects which use three part naming to refer to the containing database (hundreds of instances such as [thisDb].[dbo].[obj]* exist). I need compare and update this database, but the db project fails to build due to 200+ sql71561 errors.
I did not want to remove the unnecessary database name part or switch to using a database name variable. To successfully build, (properly) compare, and then update a database using three part naming or fully qualified naming to refer to itself, there is a way to pacify visual studio:
Create a copy of the original db project.
In the copy db project, update all local database object references to use just two part names ([dbo].[obj]) instead of three part names (I used find & replace).
Make sure the copy db project targets the same SQL server version and builds successfully.
Reference the copy db project from the original db project (whether via database variable, database name only, or dacpac).
The original db project can now build because its references can be resolved.
The original db project can now be used to update the actual database in SQL Server after a compare.
A recompare after the update shows a flawless victory.

Resources