将根目录和子目录导出到SQL Server数据库

时间:2014-02-20 20:31:10

标签: c# sql-server

我想知道有没有人知道将文件夹结构从文件系统导出到SQL Server数据库表的方法?我可以在树视图中成功创建结构,并考虑将结构导出到数据库中,但无法找出最佳方法,以便在数据库表中正确表示。基本上我要做的是创建一个具有父/子关系的递归表结构。例如 - ID, Name, Parentid,等。

如果有人有任何想法或任何想法 - 先谢谢。

修改

我可以使用树视图在UI上显示文件夹结构,没有问题,这不是问题。问题是采用该树结构并将其导出到数据库中(如上所述的父/子表示)。例如,我可以毫无问题地甚至从文件系统表示数据库中的树结构,它基本上是从文件系统中执行它并将该结构导出/导入到数据库中。把它拿出来不是问题。

希望这是有道理的。

2 个答案:

答案 0 :(得分:4)

这是一个简单的树步行。给出这样一个表:

create table dbo.directory
(
  id        int not null identity(1,1) primary key clustered ,
  parent_id int     null               foreign key references dbo.directory( id ) ,
  name      varchar(256) collate SQL_Latin1_General_CP1_CI_AS not null , -- case-insensensitive, accent-sensitive

  unique ( id , name ) ,

)
go

这样的课应该是你

class DirectoryTreeLoader : IDisposable
{
  const string          connectionString = "Server=localhost;Database=sandbox;Trusted_Connection=True;" ;
  private SqlConnection Connection       ;
  private SqlCommand    Command          ;
  private bool          CommandPrepared  ;

  private SqlParameter ParentDirectoryId ;
  private SqlParameter DirectoryName     ;

  public DirectoryTreeLoader()
  {
    Connection          = new SqlConnection(connectionString) ;
    Command             = Connection.CreateCommand() ;
    ParentDirectoryId   = new SqlParameter( "@parent_id" , SqlDbType.Int     ,   4 ) ;
    DirectoryName       = new SqlParameter( "@name"      , SqlDbType.VarChar , 256 ) ;

    ParentDirectoryId.IsNullable = true  ;

    DirectoryName.IsNullable     = false ;

    Command.Parameters.Add( ParentDirectoryId ) ;
    Command.Parameters.Add( DirectoryName     ) ;
    Command.CommandType = CommandType.Text ;
    Command.CommandText = @"
      insert dbo.directory ( parent_id , name ) values ( @parent_id , @name ) ;
      select id = scope_identity() ;
      ".Trim() ;

    return ;
  }

  public void Load( DirectoryInfo root )
  {
    if ( Connection.State == ConnectionState.Closed )
    {
      Connection.Open() ;
      Command.Prepare() ;
    }

    Visit( null , root ) ;

    return ;
  }

  private void Visit( int? parentId , DirectoryInfo dir )
  {
    // insert the current directory
    ParentDirectoryId.SqlValue = parentId.HasValue ? new SqlInt32( parentId.Value ) : SqlInt32.Null ;
    DirectoryName.SqlValue     = new SqlString( dir.Name ) ;

    object o  = Command.ExecuteScalar() ;
    int    id = (int)(decimal) o ;

    // visit each subdirectory in turn
    foreach ( DirectoryInfo subdir in dir.EnumerateDirectories() )
    {
      Visit(id,subdir) ;
    }

    return ;
  }

  public void Dispose()
  {
    if ( Command != null )
    {
      Command.Cancel();
      Command.Dispose();
      Command = null ;
    }
    if ( Connection != null )
    {
      Connection.Dispose() ;
      Connection = null ;
    }
    return ;
  }
}

用法?

static void Main( string[] args )
{
  DirectoryInfo root = new DirectoryInfo( @"c:\inetpub" ) ;
  using ( DirectoryTreeLoader loader = new DirectoryTreeLoader() )
  {
    loader.Load(root) ;
  }

  return ;
}

如果要消除递归Visit(),只需使用堆栈:

public void Load( DirectoryInfo root )
{
  if ( Connection.State == ConnectionState.Closed )
  {
    Connection.Open() ;
    Command.Prepare() ;
  }

  Stack<Tuple<int?,DirectoryInfo>> pending = new Stack<Tuple<int?, DirectoryInfo>>();
  pending.Push(new Tuple<int,DirectoryInfo>(null,root) ) ;
  while ( pending.Count > 0 )
  {
    Tuple<int?,DirectoryInfo> dir = pending.Pop() ;

    // insert the current directory
    ParentDirectoryId.SqlValue = dir.Item1.HasValue ? new SqlInt32( dir.Item1.Value ) : SqlInt32.Null ;
    DirectoryName.SqlValue     = new SqlString( dir.Item2.Name ) ;
    object o  = Command.ExecuteScalar() ;
    int parentId = (int)(decimal) o ;

    // push each subdirectory onto the stack
    foreach ( DirectoryInfo subdir in dir.Item2.EnumerateDirectories() )
    {
      pending.Push( new Tuple<int?, DirectoryInfo>(parentId,subdir));
    }

  }

  return ;
}

答案 1 :(得分:0)

你刚刚做到了。这个结构有什么问题?您可能希望添加一个属性列,您可以在其中指定对象是文件还是目录,但如果您只想记录目录结构,则每个对象(行)都是一个目录,您不需要属性列。

你可以无限期地嵌套。

现在问题是您编写客户端代码以获取嵌套结构并将其显示在UI中或者您想要使用它做什么。

要填充您的结构.net为您提供了走动要复制的文件系统所需的file system classes,您只需要在数据库中为您遇到的每个目录插入一行递归遍历目标文件系统。

更具体地说,创建一个名为“walk:”的递归函数,它接受两个参数。第一个是目录的名称,第二个是父目录的行id。在walk函数中,首先在获取作为参数传入的目录名和父ID的表。获取刚插入的行的行ID;然后调用filesystem.getdirectories函数并将其传递给目录的名称。对于该函数返回的每个目录,请调用函数返回(递归调用)传递子目录的名称和父目录的id。在你的main中,调用函数传递树的根名称作为第一个参数,零作为第二个参数,意味着根级别没有父级,它将使用您的树结构填充数据库。