Skip to content

Conversation

axelheer
Copy link
Contributor

@axelheer axelheer commented Aug 31, 2016

There isn't any handling for custom filenames within sql connection strings ('AttachDBFilename'), which leads to obscure error messages. Thus, we just add proper handling of filenames.

  • AttachDBFilename gets a reset while building master connection strings
  • Exists checks accept error 1832 and 5120 too as a hint for a non existing database
  • SqlServerCreateDatabaseOperation gets an additional FileName property

NOTE: I don't get the difference between "CreationTests" and "CreatorTests", so I just added my tests to the former ones (the other ones seem to test less related stuff).

NOTE: The changes broke a unit test, which I just changed accordingly. I'm not sure, if that's ok.

Fixes #2810

@dnfclas
Copy link

dnfclas commented Aug 31, 2016

Hi @axelheer, I'm your friendly neighborhood .NET Foundation Pull Request Bot (You can call me DNFBOT). Thanks for your contribution!
You've already signed the contribution license agreement. Thanks!

The agreement was validated by .NET Foundation and real humans are currently evaluating your PR.

TTYL, DNFBOT;

@axelheer
Copy link
Contributor Author

cc @bricelam

@axelheer axelheer changed the title Issue 2810 Add support for AttachDBFilename Aug 31, 2016

builder
.Append(" ON (NAME = '")
.Append(SqlGenerationHelper.EscapeLiteral(operation.Name))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe the filename and database name can be different. Not sure if it matters here.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll rewrite this just to make sure.

@axelheer
Copy link
Contributor Author

axelheer commented Sep 1, 2016

Any idea why the newly added tests fail on SQL 2008 and half of them on SQL 2014 (CI build)? I've only Local DB 2016; works fine.

@bricelam
Copy link
Contributor

bricelam commented Sep 2, 2016

The CI build server instances probably don't have access to %USERPROFILE%. Only LocalDB and SQL Server Express user instances (via UserInstance=True in the connection string) would...

@axelheer
Copy link
Contributor Author

axelheer commented Sep 3, 2016

  • Skip these tests, if not using LocalDB
  • Use another directory instead (which one?)

Any suggestions?

@axelheer
Copy link
Contributor Author

axelheer commented Sep 5, 2016

Okay, the older SQL Server instance seems to throw a different error, if the database does not exist.

System.Data.SqlClient.SqlException : Unable to open the physical file "C:\windows\TEMP\Scratch_3a57a202-c4b6-4b16-9e9b-e55c39ba06d7.mdf". Operating system error 2: "2(The system cannot find the file specified.)".
Cannot attach the file 'C:\windows\TEMP\Scratch_3a57a202-c4b6-4b16-9e9b-e55c39ba06d7.mdf' as database 'Scratch_3a57a202-c4b6-4b16-9e9b-e55c39ba06d7'.

Just adding a check for error number 1832 to the IsDoesNotExist method of SqlServerDatabaseCreator isn't enough then. Any idea which sql error number I should add for that? (The AppVeyor error log doesn't unveil that, and I don't want to install this locally either...) Thanks!

The error message has the corresponding sql error number 5120. I'll try another commit when I'm back home.

@bricelam
Copy link
Contributor

bricelam commented Sep 6, 2016

Skip these tests, if not using LocalDB

This one.

@axelheer
Copy link
Contributor Author

axelheer commented Sep 6, 2016

Eureka! AppVeyor went green, SQL 2008 seems to like this stuff now too. 🎉

@bricelam please let me know, if there's still something I should change.

@divega divega added this to the 1.1.0 milestone Sep 7, 2016
#else

// TODO: find proper temp directory on .NET Core. Using the current user's temp directory doesn't work,
// since the SQL Server Instance may not have access to it (running under different user credentials)...
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be addressed before merging. I think we should use AppContext.BaseDirectory and only run these tests on LocalDB. Extending the SqlServerCondition enum would be the way to do this.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay, I'll use AppDomain.BaseDirectory for classic .NET then too (consistency).

@axelheer
Copy link
Contributor Author

axelheer commented Sep 9, 2016

This time AppVeyor cannot connect to GitHub.com. The CI god ist not with me for this PR. 😔

@axelheer
Copy link
Contributor Author

@bricelam should have addressed all the feedback and Travis is green now too. Anything else I can do?

@bricelam
Copy link
Contributor

Everything looks good! I just need to find some time to bash on it a bit with various versions of SQL Server before merging.

@@ -8,5 +8,7 @@ namespace Microsoft.EntityFrameworkCore.Migrations.Operations
public class SqlServerCreateDatabaseOperation : MigrationOperation
{
public virtual string Name { get; [param: NotNull] set; }

public virtual string FileName { get; [param: NotNull] set; }
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

CanBeNull

@bricelam
Copy link
Contributor

Would you mind rebase-and-squashing on top of dev?

There isn't any handling for custom filenames within sql connection strings
('AttachDBFilename'), which leads to obscure error messages. Thus, we just
add proper handling of filenames.

* AttachDBFilename gets a reset while building master connection strings
* Exists accept error 1832 and 5120 too as a hint for non existing database
* SqlServerCreateDatabaseOperation gets an additional FileName property
@axelheer
Copy link
Contributor Author

Done.

@bricelam bricelam merged commit 6b2de53 into dotnet:dev Sep 15, 2016
@bricelam
Copy link
Contributor

Merged. Thanks for the contribution! I made a few tweaks to the tests to help me in my testing (see 656b175)

@axelheer axelheer deleted the issue-2810 branch September 16, 2016 06:28
@AzureGulf
Copy link

using VS2017 CE, C#, SQLServer 2016 LocalDb, .NET 4.6.1, EFCore 1.1.1 developing a WPF desktop app there still seems to be a problem with the connection string. Connection in App.Config is:
connectionString="Data Source=(LocalDB)\MSSQLLocalDB;AttachDbFilename=|DataDirectory|\Prices.mdf;Database=Prices.mdf;Integrated Security=True"
but DataDirectory is ignored in published (ClickOnce) version.
If running in debug (in VS) it works fine and finds the bin/Debug directory.
Only way for published version to work is if I programatically substitute the DataDirectory with the full path to the AppDomain.CurrentDomain.BaseDirectory + my relative folder (I check and create the directory if necessary). The production code also seems to ignore any settings for DataDirectory that I make to AppDomain.CurrentDomain.SetData.
In production, I am using context.Database.Migrate() to create the database (and apply migrations, still to test) so that this happens without any user intervention.
This has taken over a day to partially resolve, prior to proper testing and when combined with ongoing problems with System.Net.Http, has consumed an inordinate amount of time.
Please let me know if this AttachDbFilename issue is now fully resolved - thanks.

@ajcvickers
Copy link
Contributor

@AzureGulf EF doesn't know anything about DataDirectory--it just gets passed to DbConnection, which then handles it. However, it is my understanding that DataDirectory is not guaranteed to be set in some environments. So it would seem prudent to not use it in connection strings.

@AzureGulf
Copy link

@ajcvickers Thanks for your response and appreciate that what you say is probably correct. However, in my ignorance of DbConnection, the current mechanism is inconsistent in that it works whilst in the VS debugging version but not in the published version. Either it should work in both environments or fail in both, with a suitable error message instead of giving a run-time error in the published version.

@axelheer
Copy link
Contributor Author

Wether DataDirectory gets some love or not depends on the build being used. The full .NET Framework version supports it; the .NET Standard edition not, since there is no AppDomain available.

You can find the code here.

Maybe publishing "selects" the .NET Standard build? (I've never used ClickOnce before...)

@efidiles
Copy link

efidiles commented Jan 4, 2018

Hey guys,

We just ran into this ourselves; looks like relative paths aren't supported with AttachDbFileName.

System.Data.SqlClient.SqlException (0x80131904): Cannot attach the file '.\OurDbName.mdf' as database 'OurDbName'.

Just wanted to express that here for other people who might be bumping into this. The "fix" is use absolute paths.

@axelheer
Copy link
Contributor Author

axelheer commented Jan 4, 2018

@efidiles You can use the mighty |DataDirectory| placeholder too (see here).

@johnnyreilly
Copy link

Thanks @axelheer - we did try actually. But we just got errors when we tried... Does |DataDirectory| have any documentation?

@axelheer
Copy link
Contributor Author

axelheer commented Jan 5, 2018

@johnnyreilly none that I know of, but you can just copy the mentioned snippet to your code and test how it works... 🤔

@johnnyreilly
Copy link

Thanks @axelheer - I'll try again and report back....

@bricelam
Copy link
Contributor

bricelam commented Jan 5, 2018

You can influence |DataDirectory| by calling AppDomain.CurrentDomain.SetData("DataDirectory", "C:\My\Path").

@bricelam
Copy link
Contributor

bricelam commented Jan 5, 2018

Here is some documentation for it.

@johnnyreilly
Copy link

Thanks so much!

@zhosn
Copy link

zhosn commented Jul 14, 2019

Hey guys,
using VS2017 , C#, SQLServer 2017 LocalDb, .NET 47.2, EFCore 2.2.6 developing a WPF desktop app there still seems to be a problem when occur in SqlServerDatabaseCreator.cs. The connection string is dynamic,Connection string is:
connectionString="Data Source=(LocalDB)\MSSQLLocalDB;Database=Sundial;AttachDbFilename=
"C:\Repository\User.mdf" ;Integrated Security=True" for First execution is ok, but Connection string is:
connectionString="Data Source=(LocalDB)\MSSQLLocalDB;Database=Sundial;AttachDbFilename=
"C:\Repository\UserInfo.mdf" ;Integrated Security=True" for Second execution with error:System.Data.SqlClient.SqlException
Database 'Sundial' already exists. Choose a different database name.

Is there any way to solve the problem of adding multiple AttachDbFilename, very Thanks!

@ErikEJ
Copy link
Contributor

ErikEJ commented Jul 14, 2019

Also change the value for the Database keyword the second time

@zhosn
Copy link

zhosn commented Jul 14, 2019

Also change the value for the Database keyword the second time

Thanks @ErikEJ -But the second time I couldn't create a new database, this project had only one database: 'Sundial'。DbContext.Database.EnsureCreated() is called CreateCreateOperations() every time,but no AlterDatabaseOperation operation is performed

@ajcvickers
Copy link
Contributor

@zhosn It's not at all clear to me what you are trying to do, but if you feel there is sill a bug here, then please file a new issue and include a small, runnable project/solution or complete code listing that demonstrates the behavior you are seeing.

@zhosn
Copy link

zhosn commented Jul 16, 2019

@ajcvickers Thank you. Attached is the code list. The environment: VS2017 , C#, SQLServer 2017 LocalDb, .NET 47.2, EFCore 2.2.6
DBtest.zip

@ajcvickers
Copy link
Contributor

@zhosn Thanks for the code, but I still don't understand what it is you are attempting to do?

@zhosn
Copy link

zhosn commented Jul 18, 2019

@ajcvickers What I'm doing the project need to put each table in a single Attach Db File, not like a normal database design to unify all tables in a Attach Db File, so I will need to create multiple Attach Db Files in the database, but I don't know how to create multiple data files through the entity framework core, and in the OnModelCreating() I didn't find to create multiple additional data files, the file group and create the tables in the file group of grammar.

@ajcvickers
Copy link
Contributor

@zhosn As was stated above, there is a one-to-one relationship between database files and database names. In other words, the database file is the database. For a given database, you can't have one table in one file, and a different table in a different file--SQL Server doesn't work like that.

@zhosn
Copy link

zhosn commented Jul 19, 2019

@ajcvickers Thank you very much for your reply. At present, EF Core may not be able to solve the technical problems in my project. I started trying to use EF core for sqlite and EF core for sqlce, but both failed to solve the technical barrier of accessing multiple databases from the same Dbcontext. Now I need to find another way.

@ajcvickers ajcvickers removed this from the 1.1.0-preview1 milestone Oct 15, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

10 participants